OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / tcl8.6.12 / macosx / tclMacOSXBundle.c
diff --git a/util/src/TclTk/tcl8.6.12/macosx/tclMacOSXBundle.c b/util/src/TclTk/tcl8.6.12/macosx/tclMacOSXBundle.c
new file mode 100644 (file)
index 0000000..beef2ed
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * 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 /* 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 */
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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) {
+#if TCL_DYLD_USE_DLFCN
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
+       if (tclMacOSXDarwinRelease >= 8)
+#endif
+       {
+           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 */
+       }
+       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 */
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#undef Tcl_MacOSXOpenBundleResources
+int
+Tcl_MacOSXOpenBundleResources(
+    Tcl_Interp *interp,
+    const char *bundleName,
+    int hasResourceFile,
+    int maxPathLen,
+    char *libraryPath)
+{
+    return Tcl_MacOSXOpenVersionedBundleResources(interp, bundleName, NULL,
+           hasResourceFile, maxPathLen, libraryPath);
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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) {
+           (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) {
+#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;
+    }
+#endif /* HAVE_COREFOUNDATION */
+    return TCL_ERROR;
+}
+\f
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */