TIP #83 Version 1.6: Augment Tcl_EvalFile with Tcl_EvalChannel and Tcl_EvalUrl

This is not necessarily the current version of this TIP.


TIP:83
Title:Augment Tcl_EvalFile with Tcl_EvalChannel and Tcl_EvalUrl
Version:$Revision: 1.6 $
Authors: Marian Szczepkowski <marian at mail dot jozep dot com dot au>
dgp at users dot sf dot net
State:Withdrawn
Type:Project
Tcl-Version:8.5
Vote:Pending
Created:Thursday, 24 January 2002

Abstract

This TIP adds the ability to load Tcl files directly from URLs to the core, together with a basic mechanism to simply evaluate a stream of characters from a channel.

Proposal

I propose to split the Tcl_EvalFile function into two components to enable the [source] command to use URL's to obtain source material.

This will mean splitting Tcl_EvalFile into Tcl_EvalFile and Tcl_EvalChannel which are the two logical entities. Maintaining Tcl_EvalFile will preserve backward compatability.

Creating Tcl_EvalChannel will provide generic functionality for future use.

Adding Tcl_EvalUrl will enable handling standard URL format strings.

This would enable this [source http://anywhere.com/file.tcl] to be used.

Code will also need to be added to Tcl_SourceObjCmd to select functionality requested.

Pro.

In a corporate environment where scripts are subject to change but the interface is not, this allows scripts to be stored remotely on a central server.

This also allows Tcl to interwork in a networked environment.

Con.

Security!!!!

This may mean in the long run adding a signing layer, but don't use it if you don't want to.

Sample

I figure it looking something like this. Snipped from 8.3 source.

Tcl_SourceObjCmd

int
Tcl_SourceObjCmd(dummy, interp, objc, objv)
    ClientData dummy;		/* Not used. */
    Tcl_Interp *interp;		/* Current interpreter. */
    int objc;			/* Number of arguments. */
    Tcl_Obj *CONST objv[];	/* Argument objects. */
{
    char *bytes;
    int result;

    if (objc != 2) {
        Tcl_WrongNumArgs(interp, 1, objv, "fileName");
        return TCL_ERROR;
    }

    bytes = Tcl_GetString(objv[1]);
    if (strstr(ptr,"://")) {
        result = Tcl_EvalFile(interp, bytes);
    } else {
        result = Tcl_EvalUrl(interp, bytes);
    }
    return result;
}

Tcl_EvalFile

int
Tcl_EvalFile(interp, fileName)
    Tcl_Interp *interp;         /* Interpreter in which to process file. */
    char *fileName;             /* Name of file to process.  Tilde-substitution
                                 * will be performed on this name. */
{
    int result, length;
    struct stat statBuf;
    Interp *iPtr;
    Tcl_DString nameString;
    char *name, *string;
    Tcl_Channel chan;
    Tcl_Obj *objPtr;

    name = Tcl_TranslateFileName(interp, fileName, &nameString);
    if (name == NULL) {
        return TCL_ERROR;
    }

    result = TCL_ERROR;

    if (TclStat(name, &statBuf) == -1) {
        Tcl_SetErrno(errno);
        Tcl_AppendResult(interp, "couldn't read file \"", fileName,
                "\": ", Tcl_PosixError(interp), (char *) NULL);
        goto end;
    }

    chan = Tcl_OpenFileChannel(interp, name, "r", 0644);
    if (chan == (Tcl_Channel) NULL) {
        Tcl_ResetResult(interp);
        Tcl_AppendResult(interp, "couldn't read file \"", fileName,
                "\": ", Tcl_PosixError(interp), (char *) NULL);
        goto end;
    }

    result = Tcl_EvalChannel(interp, chan);

  end:
    Tcl_DStringFree(&nameString);
    return result;
}

Tcl_EvalUrl

int
Tcl_EvalUrl(interp, fileName)
    Tcl_Interp *interp;	/* Interpreter in which to process file. */
    char *fileName;	/* Name of URL to process. */
{
    return TCL_ERROR;
}

Tcl_EvalChannel

int
Tcl_EvalChannel(interp, chan)
    Tcl_Interp *interp; /* Interpreter in which to process file. */
    Tcl_Channel chan;   /* Name of file to process. */
{
    int result, length;
    struct stat statBuf;
    char *oldScriptFile;
    Interp *iPtr;
    char *name, *string;
    Tcl_Obj *objPtr;

    result = TCL_ERROR;
    objPtr = Tcl_NewObj();

    if (Tcl_ReadChars(chan, objPtr, -1, 0) < 0) {
        Tcl_Close(interp, chan);
        Tcl_AppendResult(interp, "couldn't read file \"", fileName,
                "\": ", Tcl_PosixError(interp), (char *) NULL);
        goto end;
    }
    if (Tcl_Close(interp, chan) != TCL_OK) {
        goto end;
    }

    iPtr = (Interp *) interp;
    oldScriptFile = iPtr->scriptFile;
    iPtr->scriptFile = fileName;
    string = Tcl_GetStringFromObj(objPtr, &length);
    result = Tcl_EvalEx(interp, string, length, 0);
    iPtr->scriptFile = oldScriptFile;

    if (result == TCL_RETURN) {
        result = TclUpdateReturnInfo(iPtr);
    } else if (result == TCL_ERROR) {
        char msg[200 + TCL_INTEGER_SPACE];

        /*
         * Record information telling where the error occurred.
         */

        sprintf(msg, "\n    (file \"%.150s\" line %d)", fileName,
                interp->errorLine);
        Tcl_AddErrorInfo(interp, msg);
    }

  end:
    Tcl_DecrRefCount(objPtr);
    return result;
}

Comments

The VFS extension interface of Tcl 8.4 plus the tclvfs and vfs::http packages provide the ability to [source] an URL. I believe that makes this proposal out of date.

Copyright

This document has been placed in the public domain.


Powered by TclThis is not necessarily the current version of this TIP.

TIP AutoGenerator - written by Donal K. Fellows