summaryrefslogtreecommitdiffstats
path: root/macosx/tclMacOSXBundle.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tclMacOSXBundle.c')
-rw-r--r--macosx/tclMacOSXBundle.c353
1 files changed, 223 insertions, 130 deletions
diff --git a/macosx/tclMacOSXBundle.c b/macosx/tclMacOSXBundle.c
index 75b871c..dad3733 100644
--- a/macosx/tclMacOSXBundle.c
+++ b/macosx/tclMacOSXBundle.c
@@ -1,63 +1,147 @@
/*
* tclMacOSXBundle.c --
*
- * This file implements functions that inspect CFBundle structures
- * on MacOS X.
- *
- * Copyright 2001, Apple Computer, Inc.
- *
- * The following terms apply to all files originating from Apple
- * Computer, Inc. ("Apple") and associated with the software
- * unless explicitly disclaimed in individual files.
- *
- *
- * Apple hereby grants permission to use, copy, modify,
- * distribute, and license this software and its documentation
- * for any purpose, provided that existing copyright notices are
- * retained in all copies and that this notice is included
- * verbatim in any distributions. No written agreement, license,
- * or royalty fee is required for any of the authorized
- * uses. Modifications to this software may be copyrighted by
- * their authors and need not follow the licensing terms
- * described here, provided that the new terms are clearly
- * indicated on the first page of each file where they apply.
- *
- *
- * IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE
- * SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
- * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
- * THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
- * EVEN IF APPLE OR THE AUTHORS HAVE BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE. APPLE, THE AUTHORS AND
- * DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS
- * SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND APPLE,THE
- * AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
- * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * GOVERNMENT USE: If you are acquiring this software on behalf
- * of the U.S. government, the Government shall have only
- * "Restricted Rights" in the software and related documentation
- * as defined in the Federal Acquisition Regulations (FARs) in
- * Clause 52.227.19 (c) (2). If you are acquiring the software
- * on behalf of the Department of Defense, the software shall be
- * classified as "Commercial Computer Software" and the
- * Government shall have only "Restricted Rights" as defined in
- * Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the
- * foregoing, the authors grant the U.S. Government and others
- * acting in its behalf permission to use and distribute the
- * software in accordance with the terms specified in this
- * license.
+ * This file implements functions that inspect CFBundle structures on
+ * MacOS X.
+ *
+ * Copyright 2001-2009, Apple Inc.
+ * Copyright (c) 2003-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
+#include "tclPort.h"
+
#ifdef HAVE_COREFOUNDATION
#include <CoreFoundation/CoreFoundation.h>
+
+#ifndef TCL_DYLD_USE_DLFCN
+/*
+ * Use preferred dlfcn API on 10.4 and later
+ */
+# if !defined(NO_DLFCN_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
+# define TCL_DYLD_USE_DLFCN 1
+# else
+# define TCL_DYLD_USE_DLFCN 0
+# endif
+#endif /* TCL_DYLD_USE_DLFCN */
+
+#ifndef TCL_DYLD_USE_NSMODULE
+/*
+ * Use deprecated NSModule API only to support 10.3 and earlier:
+ */
+# if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
+# define TCL_DYLD_USE_NSMODULE 1
+# else
+# define TCL_DYLD_USE_NSMODULE 0
+# endif
+#endif /* TCL_DYLD_USE_NSMODULE */
+
+#if TCL_DYLD_USE_DLFCN
+#include <dlfcn.h>
+#if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040
+/*
+ * Support for weakly importing dlfcn API.
+ */
+extern void * dlsym(void *handle, const char *symbol)
+ WEAK_IMPORT_ATTRIBUTE;
+extern char * dlerror(void) WEAK_IMPORT_ATTRIBUTE;
+#endif
+#endif /* TCL_DYLD_USE_DLFCN */
+
+#if TCL_DYLD_USE_NSMODULE
#include <mach-o/dyld.h>
+#endif
+
+#if (TCL_DYLD_USE_DLFCN && MAC_OS_X_VERSION_MIN_REQUIRED < 1040) || \
+ (MAC_OS_X_VERSION_MIN_REQUIRED < 1050)
+MODULE_SCOPE long tclMacOSXDarwinRelease;
+#endif
+
+#ifdef TCL_DEBUG_LOAD
+#define TclLoadDbgMsg(m, ...) \
+ do { \
+ fprintf(stderr, "%s:%d: %s(): " m ".\n", \
+ strrchr(__FILE__, '/')+1, __LINE__, __func__, \
+ ##__VA_ARGS__); \
+ } while (0)
+#else
+#define TclLoadDbgMsg(m, ...)
+#endif /* TCL_DEBUG_LOAD */
+
+/*
+ * Forward declaration of functions defined in this file:
+ */
+
+static short OpenResourceMap(CFBundleRef bundleRef);
+
#endif /* HAVE_COREFOUNDATION */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * OpenResourceMap --
+ *
+ * Wrapper that dynamically acquires the address for the function
+ * CFBundleOpenBundleResourceMap before calling it, since it is only
+ * present in full CoreFoundation on Mac OS X and not in CFLite on pure
+ * Darwin. Factored out because it is moderately ugly code.
+ *
+ *----------------------------------------------------------------------
+ */
-#include "tcl.h"
+#ifdef HAVE_COREFOUNDATION
+static short
+OpenResourceMap(
+ CFBundleRef bundleRef)
+{
+ static int initialized = FALSE;
+ static short (*openresourcemap)(CFBundleRef) = NULL;
+
+ if (!initialized) {
+#if TCL_DYLD_USE_DLFCN
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
+ if (tclMacOSXDarwinRelease >= 8)
+#endif
+ {
+ openresourcemap = dlsym(RTLD_NEXT,
+ "CFBundleOpenBundleResourceMap");
+#ifdef TCL_DEBUG_LOAD
+ if (!openresourcemap) {
+ const char *errMsg = dlerror();
+
+ TclLoadDbgMsg("dlsym() failed: %s", errMsg);
+ }
+#endif /* TCL_DEBUG_LOAD */
+ }
+ if (!openresourcemap)
+#endif /* TCL_DYLD_USE_DLFCN */
+ {
+#if TCL_DYLD_USE_NSMODULE
+ if (NSIsSymbolNameDefinedWithHint(
+ "_CFBundleOpenBundleResourceMap", "CoreFoundation")) {
+ NSSymbol nsSymbol = NSLookupAndBindSymbolWithHint(
+ "_CFBundleOpenBundleResourceMap", "CoreFoundation");
+
+ if (nsSymbol) {
+ openresourcemap = NSAddressOfSymbol(nsSymbol);
+ }
+ }
+#endif /* TCL_DYLD_USE_NSMODULE */
+ }
+ initialized = TRUE;
+ }
+
+ if (openresourcemap) {
+ return openresourcemap(bundleRef);
+ }
+ return -1;
+}
+
+#endif /* HAVE_COREFOUNDATION */
+
/*
*----------------------------------------------------------------------
*
@@ -65,13 +149,12 @@
*
* Given the bundle name for a shared library, this routine sets
* libraryPath to the Resources/Scripts directory in the framework
- * package. If hasResourceFile is true, it will also open the main
+ * package. If hasResourceFile is true, it will also open the main
* resource file for the bundle.
*
- *
* Results:
* TCL_OK if the bundle could be opened, and the Scripts folder found.
- * TCL_ERROR otherwise.
+ * TCL_ERROR otherwise.
*
* Side effects:
* libraryVariableName may be set, and the resource file opened.
@@ -82,13 +165,13 @@
int
Tcl_MacOSXOpenBundleResources(
Tcl_Interp *interp,
- CONST char *bundleName,
- int hasResourceFile,
- int maxPathLen,
- char *libraryPath)
+ const char *bundleName,
+ int hasResourceFile,
+ int maxPathLen,
+ char *libraryPath)
{
- return Tcl_MacOSXOpenVersionedBundleResources(interp, bundleName,
- NULL, hasResourceFile, maxPathLen, libraryPath);
+ return Tcl_MacOSXOpenVersionedBundleResources(interp, bundleName, NULL,
+ hasResourceFile, maxPathLen, libraryPath);
}
/*
@@ -96,16 +179,15 @@ Tcl_MacOSXOpenBundleResources(
*
* Tcl_MacOSXOpenVersionedBundleResources --
*
- * Given the bundle and version name for a shared library (version
- * name can be NULL to indicate latest version), this routine sets
- * libraryPath to the Resources/Scripts directory in the framework
- * package. If hasResourceFile is true, it will also open the main
- * resource file for the bundle.
- *
+ * Given the bundle and version name for a shared library (version name
+ * can be NULL to indicate latest version), this routine sets libraryPath
+ * to the Resources/Scripts directory in the framework package. If
+ * hasResourceFile is true, it will also open the main resource file for
+ * the bundle.
*
* Results:
* TCL_OK if the bundle could be opened, and the Scripts folder found.
- * TCL_ERROR otherwise.
+ * TCL_ERROR otherwise.
*
* Side effects:
* libraryVariableName may be set, and the resource file opened.
@@ -116,104 +198,115 @@ Tcl_MacOSXOpenBundleResources(
int
Tcl_MacOSXOpenVersionedBundleResources(
Tcl_Interp *interp,
- CONST char *bundleName,
- CONST char *bundleVersion,
- int hasResourceFile,
- int maxPathLen,
- char *libraryPath)
+ const char *bundleName,
+ const char *bundleVersion,
+ int hasResourceFile,
+ int maxPathLen,
+ char *libraryPath)
{
#ifdef HAVE_COREFOUNDATION
- CFBundleRef bundleRef;
+ CFBundleRef bundleRef, versionedBundleRef = NULL;
CFStringRef bundleNameRef;
CFURLRef libURL;
libraryPath[0] = '\0';
- bundleNameRef = CFStringCreateWithCString(NULL,
- bundleName, kCFStringEncodingUTF8);
+ bundleNameRef = CFStringCreateWithCString(NULL, bundleName,
+ kCFStringEncodingUTF8);
bundleRef = CFBundleGetBundleWithIdentifier(bundleNameRef);
CFRelease(bundleNameRef);
if (bundleVersion && bundleRef) {
- /* create bundle from bundleVersion subdirectory of 'Versions' */
- CFBundleRef versionedBundleRef = NULL;
- CFURLRef versionedBundleURL = NULL;
- CFStringRef bundleVersionRef = CFStringCreateWithCString(NULL,
- bundleVersion, kCFStringEncodingUTF8);
+ /*
+ * Create bundle from bundleVersion subdirectory of 'Versions'.
+ */
+
CFURLRef bundleURL = CFBundleCopyBundleURL(bundleRef);
+
if (bundleURL) {
- CFStringRef bundleTailRef = CFURLCopyLastPathComponent(bundleURL);
- if (bundleTailRef) {
- if (CFStringCompare(bundleTailRef,bundleVersionRef,0)
- == kCFCompareEqualTo) {
- versionedBundleRef = bundleRef;
+ CFStringRef bundleVersionRef = CFStringCreateWithCString(NULL,
+ bundleVersion, kCFStringEncodingUTF8);
+
+ if (bundleVersionRef) {
+ CFComparisonResult versionComparison = kCFCompareLessThan;
+ CFStringRef bundleTailRef = CFURLCopyLastPathComponent(
+ bundleURL);
+
+ if (bundleTailRef) {
+ versionComparison = CFStringCompare(bundleTailRef,
+ bundleVersionRef, 0);
+ CFRelease(bundleTailRef);
}
- CFRelease(bundleTailRef);
- }
- }
- if (bundleURL && !versionedBundleRef) {
- CFURLRef versURL = CFURLCreateCopyAppendingPathComponent(NULL,
- bundleURL, CFSTR("Versions"), TRUE);
- if (versURL) {
- versionedBundleURL = CFURLCreateCopyAppendingPathComponent(
- NULL, versURL, bundleVersionRef, TRUE);
- CFRelease(versURL);
+ if (versionComparison != kCFCompareEqualTo) {
+ CFURLRef versURL = CFURLCreateCopyAppendingPathComponent(
+ NULL, bundleURL, CFSTR("Versions"), TRUE);
+
+ if (versURL) {
+ CFURLRef versionedBundleURL =
+ CFURLCreateCopyAppendingPathComponent(
+ NULL, versURL, bundleVersionRef, TRUE);
+
+ if (versionedBundleURL) {
+ versionedBundleRef = CFBundleCreate(NULL,
+ versionedBundleURL);
+ if (versionedBundleRef) {
+ bundleRef = versionedBundleRef;
+ }
+ CFRelease(versionedBundleURL);
+ }
+ CFRelease(versURL);
+ }
+ }
+ CFRelease(bundleVersionRef);
}
CFRelease(bundleURL);
}
- CFRelease(bundleVersionRef);
- if (versionedBundleURL) {
- versionedBundleRef = CFBundleCreate(NULL, versionedBundleURL);
- CFRelease(versionedBundleURL);
- }
- bundleRef = versionedBundleRef;
}
- if (bundleRef) {
+ if (bundleRef) {
if (hasResourceFile) {
- /* Dynamically acquire address for CFBundleOpenBundleResourceMap
- * symbol, since it is only present in full CoreFoundation
- * on Mac OS X and not in CFLite on pure Darwin. */
- static int initialized = FALSE;
- static short (*openresourcemap)(CFBundleRef) = NULL;
- if(!initialized) {
- NSSymbol nsSymbol = NULL;
- if(NSIsSymbolNameDefinedWithHint("_CFBundleOpenBundleResourceMap", "CoreFoundation")) {
- nsSymbol = NSLookupAndBindSymbolWithHint("_CFBundleOpenBundleResourceMap", "CoreFoundation");
- if(nsSymbol) {
- openresourcemap = NSAddressOfSymbol(nsSymbol);
- }
- }
- initialized = TRUE;
- }
- if (openresourcemap) {
- short refNum;
- refNum = openresourcemap(bundleRef);
- }
+ (void) OpenResourceMap(bundleRef);
}
- libURL = CFBundleCopyResourceURL(bundleRef,
- CFSTR("Scripts"), NULL, NULL);
+ libURL = CFBundleCopyResourceURL(bundleRef, CFSTR("Scripts"),
+ NULL, NULL);
if (libURL) {
/*
- * FIXME: This is a quick fix, it is probably not right
- * for internationalization.
+ * FIXME: This is a quick fix, it is probably not right for
+ * internationalization.
*/
CFURLGetFileSystemRepresentation(libURL, TRUE,
- (unsigned char*) libraryPath, maxPathLen);
+ (unsigned char *) libraryPath, maxPathLen);
CFRelease(libURL);
}
+ if (versionedBundleRef) {
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
+ /*
+ * Workaround CFBundle bug in Tiger and earlier. [Bug 2569449]
+ */
+
+ if (tclMacOSXDarwinRelease >= 9)
+#endif
+ {
+ CFRelease(versionedBundleRef);
+ }
+ }
}
-
+
if (libraryPath[0]) {
- return TCL_OK;
- } else {
- return TCL_ERROR;
+ return TCL_OK;
}
-#else /* HAVE_COREFOUNDATION */
- return TCL_ERROR;
#endif /* HAVE_COREFOUNDATION */
+ return TCL_ERROR;
}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */