[tkined] [Fwd: tnmWinInit update to TnmInitPath()]

From: Pete Flugstad (pete_flugstad@icon-labs.com)
Date: Wed Dec 05 2001 - 16:00:10 MET


Ibid. Juergen, please let me know when you see this.

Thanks,
Pete


attached mail follows:


Please review the function TnmInitPath() in the attached file.
I've replaced the old TnmInitPath code to find the executable
name, with code to use Tcl_GetNameOfExecutable. Along with
some (heavily commented) string mangling code to look for the
other corresponding exectuable. I'm sure there's some nice
clean "Tcl" way to do this, but I don't know what it is. :-/

Hopefully this code will be independant of whatever Tcl
distribution is installed (Sun, ActiveState, TclPro, whatever).

This could be moved into a generic section of Tnm, such as
InitVars?

Pete


/*
 * tnmWinInit.c --
 *
 * This file contains the Windows specific entry point.
 *
 * Copyright (c) 1996-1997 University of Twente.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tnmInt.h"
#include "tnmPort.h"

#include <arpa/nameser.h>
#include <resolv.h>

#if defined(__WIN32__)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN

/*
 * VC++ has an alternate entry point called DllMain, so we need to rename
 * our entry point.
 */

# if defined(_MSC_VER)
# define EXPORT(a,b) __declspec(dllexport) a b
# define DllEntryPoint DllMain
# else
# if defined(__BORLANDC__)
# define EXPORT(a,b) a _export b
# else
# define EXPORT(a,b) a b
# endif
# endif
#else
# define EXPORT(a,b) a b
#endif

/*
 * Forward declarations for procedures defined later in this file:
 */

static void
FixPath _ANSI_ARGS_((char *path));

static char*
GetRegValue _ANSI_ARGS_((char *path, char *attribute));

EXTERN EXPORT(int,Tnm_Init) _ANSI_ARGS_((Tcl_Interp *interp));

EXTERN EXPORT(int,Tnm_SafeInit) _ANSI_ARGS_((Tcl_Interp *interp));


/*
 *----------------------------------------------------------------------
 *
 * DllEntryPoint --
 *
 * This wrapper function is used by Windows to invoke the
 * initialization code for the DLL. If we are compiling
 * with Visual C++, this routine will be renamed to DllMain.
 * routine.
 *
 * Results:
 * Returns TRUE;
 *
 * Side effects:
 * None.
 *
 *----------------------------------------------------------------------
 */

#ifdef __WIN32__
BOOL APIENTRY
DllEntryPoint(hInst, reason, reserved)
    HINSTANCE hInst; /* Library instance handle. */
    DWORD reason; /* Reason this function is being called. */
    LPVOID reserved; /* Not used. */
{
    return TRUE;
}
#endif

/*
 *----------------------------------------------------------------------
 *
 * FixPath --
 *
 * This procedure converts a Windows path into the Tcl
 * representation by converting "\\" to "/".
 *
 * Results:
 * None.
 *
 * Side effects:
 * The path is modified.
 *
 *----------------------------------------------------------------------
 */

static void
FixPath(path)
    char *path;
{
    if (path) {
        for (; *path; path++) {
            if (*path == '\\') {
                *path = '/';
            }
        }
    }
}

/*
 *----------------------------------------------------------------------
 *
 * GetRegValue --
 *
 * This procedure retrieves a value from the Windows registry.
 *
 * Results:
 * A pointer to the string containing the value or NULL if the
 * value can't be obtained. The string points to static memory
 * and is overwritten by every call to this procedure.
 *
 * Side effects:
 * None.
 *
 *----------------------------------------------------------------------
 */

static char *
GetRegValue(path, attribute)
    char *path;
    char *attribute;
{
    int code;
    HKEY key;
    DWORD size;
    static char *value = NULL;

    if (value) {
        ckfree(value);
        value = NULL;
    }

    code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &key);
    if (code != ERROR_SUCCESS) {
        return NULL;
    }

    code = RegQueryValueEx(key, attribute, NULL, NULL, NULL, &size);
    if (code != ERROR_SUCCESS) {
        return NULL;
    }

    value = ckalloc(size);
    code = RegQueryValueEx(key, attribute, NULL, NULL, value, &size);
    if (code != ERROR_SUCCESS) {
        ckfree(value);
        value = NULL;
    }

    return value;
}

/*
 *----------------------------------------------------------------------
 *
 * TnmInitPath --
 *
 * This procedure is called to determine the installation path
 * of the Tnm extension on this system. It uses the Windows
 * registry to retrieve the the toplevel Tnm directory name.
 *
 * Results:
 * None.
 *
 * Side effects:
 * Initializes the global Tcl variable tnm(library).
 *
 *----------------------------------------------------------------------
 */

void
TnmInitPath(interp)
    Tcl_Interp *interp;
{
    char buf[20]; /* scratch space */
    char *p, *path, *tclVersion, *tkVersion, *otherExec;
    char **pathv;
    int pathc;
    Tcl_DString ds;

    path = GetRegValue("Software\\Scotty\\Tnm\\" TNM_VERSION, "Library");
    if (! path) {
        path = getenv("TNM_LIBRARY");
        if (! path) {
            path = TNMLIB;
        }
    }
    FixPath(path);
    Tcl_SetVar2(interp, "tnm", "library", path, TCL_GLOBAL_ONLY);

    /*
     * Also initialize the tkined(library) variable which is used
     * by tnmIned.c to locate Tkined specific files. This should
     * be removed once Tkined gets integrated into Tnm.
     */

    path = GetRegValue("Software\\Scotty\\Tkined\\" TKI_VERSION, "Library");
    if (! path) {
        path = getenv("TKINED_LIBRARY");
        if (! path) {
            path = TKINEDLIB;
        }
    }
    FixPath(path);
    Tcl_SetVar2(interp, "tkined", "library", path, TCL_GLOBAL_ONLY);

    /*
     * Locate tclsh and wish so that we can start additional
     * scripts with the correct path name.
     */

    /* first, get the tcl/tk version information */
    Tcl_DStringInit(&ds);
    tclVersion = Tcl_GetVar(interp, "tcl_version", TCL_GLOBAL_ONLY);
    tkVersion = Tcl_GetVar(interp, "tk_version", TCL_GLOBAL_ONLY);

    /* use Tcl_GetNameOfExecutable() to get full path of current executable */
    Tcl_SplitPath( Tcl_GetNameOfExecutable(), &pathc, &pathv );
    Tcl_JoinPath( pathc, pathv, &ds );

    /* this could be tclsh or wish */
    if ( strncmp( pathv[pathc-1], "tclsh", 5 ) == 0 ) {
        Tcl_SetVar2(interp, "tnm", "tclsh", Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY);
        otherExec = "wish";
    }
    else if ( strncmp( pathv[pathc-1], "wish", 4 ) == 0 ) {
        Tcl_SetVar2(interp, "tnm", "wish", Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY);
        otherExec = "tclsh";
    }
    else /* unknown executable - should probably print out some kind of error msg?? */
        return;

    /* we're done using current DString value */
    Tcl_DStringFree(&ds);

    /* now, we need to find the corresponding other executable */
    /* build up the name wish<ver>.exe */
    memset( buf, 0, sizeof(buf) );
    strcat( buf, otherExec );
    path = buf + strlen(buf);
        
    for (p = tclVersion; *p && path < (buf+sizeof(buf)); p++) {
        if (isdigit(*p)) *path++ = *p;
    }
    *path = '\0'; /* null terminate */
    strcat( buf, ".exe" );
    
    /* replace last entry in pathv with the name of wish */
    /* this is not a memory leak since pathv memory is
     * contiguously allocated and so it'll all be freed when
     * we free pathv below */
    pathv[pathc-1] = buf;
    
    /* now reconstruct the path and see if we have our wish */
    Tcl_JoinPath( pathc, pathv, &ds );
    
    if (access(Tcl_DStringValue(&ds), R_OK | X_OK) == 0) {
        Tcl_SetVar2(interp, "tnm", otherExec,
                    Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY);
    }
    Tcl_DStringFree(&ds);
    Tcl_Free( (char *)pathv );
}

/*
 *----------------------------------------------------------------------
 *
 * TnmInitDns --
 *
 * This procedure is called to initialize the DNS resolver and to
 * save the domain name in the global tnm(domain) Tcl variable.
 *
 * Results:
 * None.
 *
 * Side effects:
 * None.
 *
 *----------------------------------------------------------------------
 */

void
TnmInitDns(interp)
    Tcl_Interp *interp;
{
    char domain[MAXDNAME], *p;
    char *nameServer = NULL, *domainName = NULL;
    int i;

    char *paths[] = {
        "System\\CurrentControlSet\\Services\\TcpIP\\Parameters",
        "System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
        "System\\CurrentControlSet\\Services\\VxD\\MSTCP",
        NULL
    };

    res_init();
    _res.options |= RES_RECURSE | RES_DNSRCH | RES_DEFNAMES | RES_AAONLY;
    
    /*
     * Get the list of name servers from the Windows registry and set
     * the list of default DNS servers. Note, this should be done
     * automatically by the resolver but it is obviously not on
     * Windows machines.
     */

    for (i = 0; paths[i] && ! nameServer; i++) {
        nameServer = GetRegValue(paths[i], "NameServer");
        if (nameServer) {
            int n = 0;
            char *s = strtok(nameServer, ", ");
            while (s && n < MAXNS) {
                TnmSetIPAddress((Tcl_Interp *) NULL, s, &_res.nsaddr_list[n]);
                s = strtok(NULL, ", ");
                n++;
            }
            _res.nscount = n;
        }
    }

    if (! nameServer) {
        TnmSetIPAddress((Tcl_Interp *) NULL,
                        "127.0.0.1", &_res.nsaddr_list[0]);
        _res.nscount = 1;
    }

    /* Get the domain name form the Windows registry and set the
     * default domain name for the resolver, if not done
     * automatically. */

    for (i = 0; paths[i] && ! domainName; i++) {
        domainName = GetRegValue(paths[i], "Domain");
    }

    if (! _res.defdname[0] && domainName && strlen(domainName) < MAXDNAME) {
        strcpy(_res.defdname, domainName);
    }

    /*
     * Remove the any trailing dots or white spaces and save the
     * result in tnm(domain).
     */

    strcpy(domain, _res.defdname);
    p = domain + strlen(domain) - 1;
    while ((*p == '.' || isspace(*p)) && p > domain) {
        *p-- = '\0';
    }
    Tcl_SetVar2(interp, "tnm", "domain", domain, TCL_GLOBAL_ONLY);
}

/*
 *----------------------------------------------------------------------
 *
 * Tnm_Init --
 *
 * This procedure is the Windows entry point for trusted Tcl
 * interpreters.
 *
 * Results:
 * A standard Tcl result.
 *
 * Side effects:
 * Tcl variables are created.
 *
 *----------------------------------------------------------------------
 */

EXPORT(int,Tnm_Init)(interp)
    Tcl_Interp *interp;
{
    return TnmInit(interp, 0);
}

/*
 *----------------------------------------------------------------------
 *
 * Tnm_SafeInit --
 *
 * This procedure is the Windows entry point for safe Tcl
 * interpreters.
 *
 * Results:
 * A standard Tcl result.
 *
 * Side effects:
 * Tcl variables are created.
 *
 *----------------------------------------------------------------------
 */

EXPORT(int,Tnm_SafeInit)(interp)
    Tcl_Interp *interp;
{
    return TnmInit(interp, 1);
}

--
!! This message is brought to you via the `tkined & scotty' mailing list.
!! Please do not reply to this message to unsubscribe. To subscribe or
!! unsubscribe, send a mail message to <tkined-request@ibr.cs.tu-bs.de>.
!! See http://wwwsnmp.cs.utwente.nl/~schoenw/scotty/ for more information.



This archive was generated by hypermail 2b29 : Thu Jan 03 2002 - 14:56:28 MET