sl@0: /* 
sl@0:  * tclLoadDl.c --
sl@0:  *
sl@0:  *	This procedure provides a version of the TclLoadFile that
sl@0:  *	works with the "dlopen" and "dlsym" library procedures for
sl@0:  *	dynamic loading.
sl@0:  *
sl@0:  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
sl@0:  *
sl@0:  * See the file "license.terms" for information on usage and redistribution
sl@0:  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0:  *
sl@0:  * RCS: @(#) $Id: tclLoadDl.c,v 1.13.2.1 2006/06/13 22:54:01 dkf Exp $
sl@0:  */
sl@0: 
sl@0: #include "tclInt.h"
sl@0: #ifdef NO_DLFCN_H
sl@0: #   include "../compat/dlfcn.h"
sl@0: #else
sl@0: #   include <dlfcn.h>
sl@0: #endif
sl@0: 
sl@0: /*
sl@0:  * In some systems, like SunOS 4.1.3, the RTLD_NOW flag isn't defined
sl@0:  * and this argument to dlopen must always be 1.  The RTLD_GLOBAL
sl@0:  * flag is needed on some systems (e.g. SCO and UnixWare) but doesn't
sl@0:  * exist on others;  if it doesn't exist, set it to 0 so it has no effect.
sl@0:  */
sl@0: 
sl@0: #ifndef RTLD_NOW
sl@0: #   define RTLD_NOW 1
sl@0: #endif
sl@0: 
sl@0: #ifndef RTLD_GLOBAL
sl@0: #   define RTLD_GLOBAL 0
sl@0: #endif
sl@0: 
sl@0: /*
sl@0:  *---------------------------------------------------------------------------
sl@0:  *
sl@0:  * TclpDlopen --
sl@0:  *
sl@0:  *	Dynamically loads a binary code file into memory and returns
sl@0:  *	a handle to the new code.
sl@0:  *
sl@0:  * Results:
sl@0:  *	A standard Tcl completion code.  If an error occurs, an error
sl@0:  *	message is left in the interp's result. 
sl@0:  *
sl@0:  * Side effects:
sl@0:  *	New code suddenly appears in memory.
sl@0:  *
sl@0:  *---------------------------------------------------------------------------
sl@0:  */
sl@0: 
sl@0: int
sl@0: TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
sl@0:     Tcl_Interp *interp;		/* Used for error reporting. */
sl@0:     Tcl_Obj *pathPtr;		/* Name of the file containing the desired
sl@0: 				 * code (UTF-8). */
sl@0:     Tcl_LoadHandle *loadHandle;	/* Filled with token for dynamically loaded
sl@0: 				 * file which will be passed back to 
sl@0: 				 * (*unloadProcPtr)() to unload the file. */
sl@0:     Tcl_FSUnloadFileProc **unloadProcPtr;	
sl@0: 				/* Filled with address of Tcl_FSUnloadFileProc
sl@0: 				 * function which should be used for
sl@0: 				 * this file. */
sl@0: {
sl@0:     VOID *handle;
sl@0:     CONST char *native;
sl@0: 
sl@0:     /* 
sl@0:      * First try the full path the user gave us.  This is particularly
sl@0:      * important if the cwd is inside a vfs, and we are trying to load
sl@0:      * using a relative path.
sl@0:      */
sl@0:     native = Tcl_FSGetNativePath(pathPtr);
sl@0:     handle = dlopen(native, RTLD_NOW | RTLD_GLOBAL);
sl@0:     if (handle == NULL) {
sl@0: 	/* 
sl@0: 	 * Let the OS loader examine the binary search path for
sl@0: 	 * whatever string the user gave us which hopefully refers
sl@0: 	 * to a file on the binary path
sl@0: 	 */
sl@0: 	Tcl_DString ds;
sl@0: 	char *fileName = Tcl_GetString(pathPtr);
sl@0: 	native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
sl@0: 	handle = dlopen(native, RTLD_NOW | RTLD_GLOBAL);
sl@0: 	Tcl_DStringFree(&ds);
sl@0:     }
sl@0:     
sl@0:     if (handle == NULL) {
sl@0: 	/*
sl@0: 	 * Write the string to a variable first to work around a compiler bug
sl@0: 	 * in the Sun Forte 6 compiler. [Bug 1503729]
sl@0: 	 */
sl@0: 
sl@0: 	CONST char *errorStr = dlerror();
sl@0: 
sl@0: 	Tcl_AppendResult(interp, "couldn't load file \"", 
sl@0: 		Tcl_GetString(pathPtr), "\": ", errorStr, (char *) NULL);
sl@0: 	return TCL_ERROR;
sl@0:     }
sl@0: 
sl@0:     *unloadProcPtr = &TclpUnloadFile;
sl@0:     *loadHandle = (Tcl_LoadHandle)handle;
sl@0:     return TCL_OK;
sl@0: }
sl@0: 
sl@0: /*
sl@0:  *----------------------------------------------------------------------
sl@0:  *
sl@0:  * TclpFindSymbol --
sl@0:  *
sl@0:  *	Looks up a symbol, by name, through a handle associated with
sl@0:  *	a previously loaded piece of code (shared library).
sl@0:  *
sl@0:  * Results:
sl@0:  *	Returns a pointer to the function associated with 'symbol' if
sl@0:  *	it is found.  Otherwise returns NULL and may leave an error
sl@0:  *	message in the interp's result.
sl@0:  *
sl@0:  *----------------------------------------------------------------------
sl@0:  */
sl@0: Tcl_PackageInitProc*
sl@0: TclpFindSymbol(interp, loadHandle, symbol) 
sl@0:     Tcl_Interp *interp;
sl@0:     Tcl_LoadHandle loadHandle;
sl@0:     CONST char *symbol;
sl@0: {
sl@0:     CONST char *native;
sl@0:     Tcl_DString newName, ds;
sl@0:     VOID *handle = (VOID*)loadHandle;
sl@0:     Tcl_PackageInitProc *proc;
sl@0:     /* 
sl@0:      * Some platforms still add an underscore to the beginning of symbol
sl@0:      * names.  If we can't find a name without an underscore, try again
sl@0:      * with the underscore.
sl@0:      */
sl@0: 
sl@0:     native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
sl@0:     proc = (Tcl_PackageInitProc *) dlsym(handle,	/* INTL: Native. */
sl@0: 	    native);	
sl@0:     if (proc == NULL) {
sl@0: 	Tcl_DStringInit(&newName);
sl@0: 	Tcl_DStringAppend(&newName, "_", 1);
sl@0: 	native = Tcl_DStringAppend(&newName, native, -1);
sl@0: 	proc = (Tcl_PackageInitProc *) dlsym(handle, /* INTL: Native. */
sl@0: 		native);
sl@0: 	Tcl_DStringFree(&newName);
sl@0:     }
sl@0:     Tcl_DStringFree(&ds);
sl@0: 
sl@0:     return proc;
sl@0: }
sl@0: 
sl@0: /*
sl@0:  *----------------------------------------------------------------------
sl@0:  *
sl@0:  * TclpUnloadFile --
sl@0:  *
sl@0:  *	Unloads a dynamically loaded binary code file from memory.
sl@0:  *	Code pointers in the formerly loaded file are no longer valid
sl@0:  *	after calling this function.
sl@0:  *
sl@0:  * Results:
sl@0:  *	None.
sl@0:  *
sl@0:  * Side effects:
sl@0:  *	Code removed from memory.
sl@0:  *
sl@0:  *----------------------------------------------------------------------
sl@0:  */
sl@0: 
sl@0: void
sl@0: TclpUnloadFile(loadHandle)
sl@0:     Tcl_LoadHandle loadHandle;	/* loadHandle returned by a previous call
sl@0: 				 * to TclpDlopen().  The loadHandle is 
sl@0: 				 * a token that represents the loaded 
sl@0: 				 * file. */
sl@0: {
sl@0:     VOID *handle;
sl@0: 
sl@0:     handle = (VOID *) loadHandle;
sl@0:     dlclose(handle);
sl@0: }
sl@0: 
sl@0: /*
sl@0:  *----------------------------------------------------------------------
sl@0:  *
sl@0:  * TclGuessPackageName --
sl@0:  *
sl@0:  *	If the "load" command is invoked without providing a package
sl@0:  *	name, this procedure is invoked to try to figure it out.
sl@0:  *
sl@0:  * Results:
sl@0:  *	Always returns 0 to indicate that we couldn't figure out a
sl@0:  *	package name;  generic code will then try to guess the package
sl@0:  *	from the file name.  A return value of 1 would have meant that
sl@0:  *	we figured out the package name and put it in bufPtr.
sl@0:  *
sl@0:  * Side effects:
sl@0:  *	None.
sl@0:  *
sl@0:  *----------------------------------------------------------------------
sl@0:  */
sl@0: 
sl@0: int
sl@0: TclGuessPackageName(fileName, bufPtr)
sl@0:     CONST char *fileName;	/* Name of file containing package (already
sl@0: 				 * translated to local form if needed). */
sl@0:     Tcl_DString *bufPtr;	/* Initialized empty dstring.  Append
sl@0: 				 * package name to this if possible. */
sl@0: {
sl@0:     return 0;
sl@0: }