TIP: 83 Title: Augment Tcl_EvalFile with Tcl_EvalChannel and Tcl_EvalUrl Version: $Revision: 1.6 $ Author: Marian Szczepkowski Author: State: Withdrawn Type: Project Vote: Pending Created: 24-Jan-2002 Post-History: Tcl-Version: 8.5 ~ 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.