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 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
|
/*
* tclMacOSXBundle.c --
*
* This file implements functions that inspect CFBundle structures on
* MacOS X.
*
* Copyright © 2001-2009 Apple Inc.
* Copyright © 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"
#include "tclInt.h"
#ifdef HAVE_COREFOUNDATION
#include <CoreFoundation/CoreFoundation.h>
#include <dlfcn.h>
#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.
*
*----------------------------------------------------------------------
*/
#ifdef HAVE_COREFOUNDATION
static short
OpenResourceMap(
CFBundleRef bundleRef)
{
static int initialized = FALSE;
static short (*openresourcemap)(CFBundleRef) = NULL;
if (!initialized) {
{
openresourcemap = (short (*)(CFBundleRef))dlsym(RTLD_NEXT,
"CFBundleOpenBundleResourceMap");
#ifdef TCL_DEBUG_LOAD
if (!openresourcemap) {
const char *errMsg = dlerror();
TclLoadDbgMsg("dlsym() failed: %s", errMsg);
}
#endif /* TCL_DEBUG_LOAD */
}
initialized = TRUE;
}
if (openresourcemap) {
return openresourcemap(bundleRef);
}
return -1;
}
#endif /* HAVE_COREFOUNDATION */
/*
*----------------------------------------------------------------------
*
* 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_UNUSED(Tcl_Interp *),
const char *bundleName,
const char *bundleVersion,
int hasResourceFile,
Tcl_Size 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) {
(void) 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) {
{
CFRelease(versionedBundleRef);
}
}
}
if (libraryPath[0]) {
return TCL_OK;
}
#endif /* HAVE_COREFOUNDATION */
return TCL_ERROR;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|