TIP #83: Augment Tcl_EvalFile with Tcl_EvalChannel and Tcl_EvalUrl
_____________________________________________________________________________
TIP:	83
Title:	Augment Tcl_EvalFile with Tcl_EvalChannel and Tcl_EvalUrl
Version:	$Revision: 1.6 $
Authors:	Marian Szczepkowski <marian@mail.jozep.com.au>
	<dgp@users.sf.net>
State:	Withdrawn
Type:	Project
Tcl-Version:	8.5
Vote:	Pending
Created:	Thu Jan 24 00:00:00 UTC 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, "   (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.
_____________________________________________________________________________
Colophon
TIP AutoGenerator - written by Donal K. Fellows