Import Tcl 8.5.15 (as of svn r89086)
This commit is contained in:
286
macosx/tclMacOSXBundle.c
Normal file
286
macosx/tclMacOSXBundle.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* tclMacOSXBundle.c --
|
||||
*
|
||||
* 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
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
|
||||
#endif /* HAVE_COREFOUNDATION */
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_MacOSXOpenBundleResources --
|
||||
*
|
||||
* 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
|
||||
* resource file for the bundle.
|
||||
*
|
||||
* Results:
|
||||
* TCL_OK if the bundle could be opened, and the Scripts folder found.
|
||||
* TCL_ERROR otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* libraryVariableName may be set, and the resource file opened.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
Tcl_MacOSXOpenBundleResources(
|
||||
Tcl_Interp *interp,
|
||||
CONST char *bundleName,
|
||||
int hasResourceFile,
|
||||
int maxPathLen,
|
||||
char *libraryPath)
|
||||
{
|
||||
return Tcl_MacOSXOpenVersionedBundleResources(interp, bundleName,
|
||||
NULL, hasResourceFile, maxPathLen, libraryPath);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Results:
|
||||
* TCL_OK if the bundle could be opened, and the Scripts folder found.
|
||||
* TCL_ERROR otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* libraryVariableName may be set, and the resource file opened.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
Tcl_MacOSXOpenVersionedBundleResources(
|
||||
Tcl_Interp *interp,
|
||||
CONST char *bundleName,
|
||||
CONST char *bundleVersion,
|
||||
int hasResourceFile,
|
||||
int maxPathLen,
|
||||
char *libraryPath)
|
||||
{
|
||||
#ifdef HAVE_COREFOUNDATION
|
||||
CFBundleRef bundleRef, versionedBundleRef = NULL;
|
||||
CFStringRef bundleNameRef;
|
||||
CFURLRef libURL;
|
||||
|
||||
libraryPath[0] = '\0';
|
||||
|
||||
bundleNameRef = CFStringCreateWithCString(NULL, bundleName,
|
||||
kCFStringEncodingUTF8);
|
||||
|
||||
bundleRef = CFBundleGetBundleWithIdentifier(bundleNameRef);
|
||||
CFRelease(bundleNameRef);
|
||||
|
||||
if (bundleVersion && bundleRef) {
|
||||
/*
|
||||
* Create bundle from bundleVersion subdirectory of 'Versions'.
|
||||
*/
|
||||
|
||||
CFURLRef bundleURL = CFBundleCopyBundleURL(bundleRef);
|
||||
|
||||
if (bundleURL) {
|
||||
CFStringRef bundleVersionRef = CFStringCreateWithCString(NULL,
|
||||
bundleVersion, kCFStringEncodingUTF8);
|
||||
|
||||
if (bundleVersionRef) {
|
||||
CFComparisonResult versionComparison = kCFCompareLessThan;
|
||||
CFStringRef bundleTailRef = CFURLCopyLastPathComponent(
|
||||
bundleURL);
|
||||
|
||||
if (bundleTailRef) {
|
||||
versionComparison = CFStringCompare(bundleTailRef,
|
||||
bundleVersionRef, 0);
|
||||
CFRelease(bundleTailRef);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
#if TCL_DYLD_USE_DLFCN
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
|
||||
if (tclMacOSXDarwinRelease >= 8)
|
||||
#endif
|
||||
{
|
||||
const char *errMsg = nil;
|
||||
openresourcemap = dlsym(RTLD_NEXT,
|
||||
"CFBundleOpenBundleResourceMap");
|
||||
if (!openresourcemap) {
|
||||
errMsg = dlerror();
|
||||
TclLoadDbgMsg("dlsym() failed: %s", errMsg);
|
||||
}
|
||||
}
|
||||
if (!openresourcemap)
|
||||
#endif
|
||||
{
|
||||
#if TCL_DYLD_USE_NSMODULE
|
||||
NSSymbol nsSymbol = NULL;
|
||||
if (NSIsSymbolNameDefinedWithHint(
|
||||
"_CFBundleOpenBundleResourceMap",
|
||||
"CoreFoundation")) {
|
||||
nsSymbol = NSLookupAndBindSymbolWithHint(
|
||||
"_CFBundleOpenBundleResourceMap",
|
||||
"CoreFoundation");
|
||||
if (nsSymbol) {
|
||||
openresourcemap = NSAddressOfSymbol(nsSymbol);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
if (openresourcemap) {
|
||||
short refNum;
|
||||
|
||||
refNum = openresourcemap(bundleRef);
|
||||
}
|
||||
}
|
||||
|
||||
libURL = CFBundleCopyResourceURL(bundleRef, CFSTR("Scripts"),
|
||||
NULL, NULL);
|
||||
|
||||
if (libURL) {
|
||||
/*
|
||||
* FIXME: This is a quick fix, it is probably not right for
|
||||
* internationalization.
|
||||
*/
|
||||
|
||||
CFURLGetFileSystemRepresentation(libURL, TRUE,
|
||||
(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;
|
||||
}
|
||||
#else /* HAVE_COREFOUNDATION */
|
||||
return TCL_ERROR;
|
||||
#endif /* HAVE_COREFOUNDATION */
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: c
|
||||
* c-basic-offset: 4
|
||||
* fill-column: 78
|
||||
* End:
|
||||
*/
|
||||
Reference in New Issue
Block a user