\documentclass[]{article}
\usepackage{amsmath,graphicx,supertabular,hyperref,tabularx,ifthen}
\title{TIP \#83: Augment Tcl\_EvalFile with Tcl\_EvalChannel and Tcl\_EvalUrl}
\date{January 24, 2002}
\author{Marian Szczepkowski, }
\urlstyle{sf}
\setlength{\parskip}{1ex}
\setlength{\parindent}{0pt}
\def\tipversion$#1${\texttt{\$#1\$}}
\def\tiplangle#1{\ensuremath{<}}
\def\tiprangle#1{\ensuremath{>}}
\def\tipbar#1{\ensuremath{|}}
\def\tipmail#1#2{\(\langle\){\small\expandafter\url{#1@#2}}\(\rangle\)}
\ifx\pdfoutput\undefined
\newcommand{\tipimage}[2]{\typeout{Make sure you download #1.eps}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.eps}}{\includegraphics[width=0.8\textwidth]{#1.eps}}}
\newcommand{\tipxref}[1]{}
\newcommand{\tipxrefend}{}
\else
\newcommand{\tipimage}[2]{\typeout{Make sure you create #1.pdf}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.pdf}}{\includegraphics[width=0.8\textwidth]{#1.pdf}}}
\pdfcatalog{/PageMode /UseOutlines}
\newcommand{\tipxref}[1]{\pdfannotlink attr {/C [0.5 0.5 1.0] /Border [0 0 1]} goto name {#1}}
\newcommand{\tipxrefend}{\pdfendlink}
\fi
\newenvironment{tipabstract}{\begin{abstract}}{\end{abstract}}
\begin{document}\maketitle
\begin{center}\begin{tabularx}{\linewidth}{|r@{: }X|}\hline
\textbf{TIP \#83}&\textbf{Augment Tcl\_EvalFile with Tcl\_EvalChannel and Tcl\_EvalUrl}\\\hline
Author&

Marian Szczepkowski \tipmail{marian}{mail.jozep.com.au}
\par
\tipmail{dgp}{users.sf.net}
\\
Created&Thursday, \(\text{24}^{\text{th}}\) January 2002\\
Type&Project\\
Tcl Version&\(8.5\)\\
State&Withdrawn\\
Vote&Pending\\
Version&\tipversion$Revision: 1.6 $\\
Post History&\\
\hline\end{tabularx}\end{center}
\thispagestyle{empty}\pagestyle{empty}
\begin{tipabstract}

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.
\end{tipabstract}
\tableofcontents\setcounter{page}{0}\clearpage\pagestyle{plain}

\section{Proposal}

I propose to split the \textit{Tcl\_EvalFile} function into two components to enable the [source] command to use URL's to obtain source material.

This will mean splitting \textit{Tcl\_EvalFile} into \textit{Tcl\_EvalFile} and \textit{Tcl\_EvalChannel} which are the two logical entities. Maintaining \textit{Tcl\_EvalFile} will preserve backward compatability.

Creating \textit{Tcl\_EvalChannel} will provide generic functionality for future use.

Adding \textit{Tcl\_EvalUrl} will enable handling standard URL format strings.

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

Code will also need to be added to \textit{Tcl\_SourceObjCmd} to select functionality requested.

\section{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.

\section{Con.}

Security!!!!

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

\section{Sample}

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

\section{Tcl\_SourceObjCmd}
\begingroup\small\begin{verbatim}
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;
}
\end{verbatim}
\endgroup

\section{Tcl\_EvalFile}
\begingroup\small\begin{verbatim}
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;
}
\end{verbatim}
\endgroup

\section{Tcl\_EvalUrl}
\begingroup\small\begin{verbatim}
int
Tcl_EvalUrl(interp, fileName)
    Tcl_Interp *interp;	/* Interpreter in which to process file. */
    char *fileName;	/* Name of URL to process. */
{
    return TCL_ERROR;
}
\end{verbatim}
\endgroup

\section{Tcl\_EvalChannel}
\begingroup\small\begin{verbatim}
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;
}
\end{verbatim}
\endgroup

\section{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.

\section{Copyright}

This document has been placed in the public domain.

\section{Colophon}

\textit{TIP AutoGenerator --- written by Donal K. Fellows}
\end{document}
