Skip to content

Commit 395d3d0

Browse files
committed
Implement TIP 728: interp set
2 parents f2b5753 + e44e9d0 commit 395d3d0

File tree

5 files changed

+284
-18
lines changed

5 files changed

+284
-18
lines changed

doc/interp.n

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,16 @@ may get stack overflows before reaching the limit set by the command. If
390390
this happens, see if there is a mechanism in your system for increasing
391391
the maximum size of the C stack.
392392
.RE
393+
.\" METHOD: set
394+
.TP
395+
\fBinterp set\fI path varName\fR ?\fIvalue\fR?
396+
.VS 9.1
397+
Writes to, or reads from, the variable \fIvarName\fR in the interpreter
398+
specifed by \fIpath\fR. If \fIvalue\fR is given, writes to the variable and
399+
returns its new value; if \fIvalue\fR is omitted, reads from the variable.
400+
As with the \fBset\fR command, traces may affect what the value of the
401+
variable is.
402+
.VE 9.1
393403
.\" METHOD: share
394404
.TP
395405
\fBinterp share\fI srcPath channel destPath\fR
@@ -601,6 +611,17 @@ may get stack overflows before reaching the limit set by the command. If
601611
this happens, see if there is a mechanism in your system for increasing
602612
the maximum size of the C stack.
603613
.RE
614+
.RE
615+
.\" METHOD: set
616+
.TP
617+
\fIchild \fBset\fR \fIvarName\fR ?\fIvalue\fR?
618+
.VS 9.1
619+
Writes to, or reads from, the variable \fIvarName\fR in the \fIchild\fR
620+
interpreter. If \fIvalue\fR is given, writes to the variable and
621+
returns its new value; if \fIvalue\fR is omitted, reads from the variable.
622+
As with the \fBset\fR command, traces may affect what the value of the
623+
variable is.
624+
.VE 9.1
604625
.SH "SAFE INTERPRETERS"
605626
.PP
606627
A safe interpreter is one with restricted functionality, so that

generic/tclInterp.c

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ static int ChildInvokeHidden(Tcl_Interp *interp,
256256
static int ChildMarkTrusted(Tcl_Interp *interp,
257257
Tcl_Interp *childInterp);
258258
static Tcl_CmdDeleteProc ChildObjCmdDeleteProc;
259+
static int ChildSet(Tcl_Interp *interp,
260+
Tcl_Interp *childInterp, Tcl_Obj *varNameObj,
261+
Tcl_Obj *valueObj);
259262
static int ChildRecursionLimit(Tcl_Interp *interp,
260263
Tcl_Interp *childInterp, Tcl_Size objc,
261264
Tcl_Obj *const objv[]);
@@ -635,7 +638,7 @@ NRInterpCmd(
635638
"eval", "exists", "expose", "hide",
636639
"hidden", "issafe", "invokehidden",
637640
"limit", "marktrusted", "recursionlimit",
638-
"share",
641+
"set", "share",
639642
#ifndef TCL_NO_DEPRECATED
640643
"slaves",
641644
#endif
@@ -647,15 +650,16 @@ NRInterpCmd(
647650
"eval", "exists", "expose",
648651
"hide", "hidden", "issafe",
649652
"invokehidden", "limit", "marktrusted", "recursionlimit",
650-
"share", "target", "transfer",
653+
"set", "share", "target", "transfer",
651654
NULL
652655
};
653656
enum interpOptionEnum {
654657
OPT_ALIAS, OPT_ALIASES, OPT_BGERROR, OPT_CANCEL,
655658
OPT_CHILDREN, OPT_CREATE, OPT_DEBUG, OPT_DELETE,
656659
OPT_EVAL, OPT_EXISTS, OPT_EXPOSE, OPT_HIDE,
657660
OPT_HIDDEN, OPT_ISSAFE, OPT_INVOKEHID,
658-
OPT_LIMIT, OPT_MARKTRUSTED, OPT_RECLIMIT, OPT_SHARE,
661+
OPT_LIMIT, OPT_MARKTRUSTED, OPT_RECLIMIT, OPT_SET,
662+
OPT_SHARE,
659663
#ifndef TCL_NO_DEPRECATED
660664
OPT_SLAVES,
661665
#endif
@@ -903,6 +907,17 @@ NRInterpCmd(
903907
return TCL_ERROR;
904908
}
905909
return ChildEval(interp, childInterp, objc - 3, objv + 3);
910+
case OPT_SET:
911+
if (objc < 4 || objc > 5) {
912+
Tcl_WrongNumArgs(interp, 2, objv, "path varName ?value?");
913+
return TCL_ERROR;
914+
}
915+
childInterp = GetInterp(interp, objv[2]);
916+
if (childInterp == NULL) {
917+
return TCL_ERROR;
918+
}
919+
return ChildSet(interp, childInterp, objv[3],
920+
objc > 4 ? objv[4] : NULL);
906921
case OPT_EXISTS: {
907922
int exists = 1;
908923

@@ -2521,13 +2536,13 @@ NRChildCmd(
25212536
"alias", "aliases", "bgerror", "debug",
25222537
"eval", "expose", "hide", "hidden",
25232538
"issafe", "invokehidden", "limit", "marktrusted",
2524-
"recursionlimit", NULL
2539+
"recursionlimit", "set", NULL
25252540
};
25262541
enum childCmdOptionsEnum {
25272542
OPT_ALIAS, OPT_ALIASES, OPT_BGERROR, OPT_DEBUG,
25282543
OPT_EVAL, OPT_EXPOSE, OPT_HIDE, OPT_HIDDEN,
25292544
OPT_ISSAFE, OPT_INVOKEHIDDEN, OPT_LIMIT, OPT_MARKTRUSTED,
2530-
OPT_RECLIMIT
2545+
OPT_RECLIMIT, OPT_SET
25312546
} index;
25322547

25332548
if (childInterp == NULL) {
@@ -2689,6 +2704,12 @@ NRChildCmd(
26892704
return TCL_ERROR;
26902705
}
26912706
return ChildRecursionLimit(interp, childInterp, objc - 2, objv + 2);
2707+
case OPT_SET:
2708+
if (objc < 3 || objc > 4) {
2709+
Tcl_WrongNumArgs(interp, 2, objv, "varName ?value?");
2710+
return TCL_ERROR;
2711+
}
2712+
return ChildSet(interp, childInterp, objv[2], objc>3 ? objv[3] : NULL);
26922713
default:
26932714
TCL_UNREACHABLE();
26942715
}
@@ -2878,6 +2899,51 @@ ChildEval(
28782899
return result;
28792900
}
28802901

2902+
/*
2903+
*----------------------------------------------------------------------
2904+
*
2905+
* ChildSet --
2906+
*
2907+
* Helper function to read and write a variable in a child interpreter.
2908+
*
2909+
* Results:
2910+
* A standard Tcl result.
2911+
*
2912+
* Side effects:
2913+
* Depends on whether the variable has traces. If so, this can have
2914+
* extensive arbitrary side effects.
2915+
*
2916+
*----------------------------------------------------------------------
2917+
*/
2918+
static int
2919+
ChildSet(
2920+
Tcl_Interp *interp,
2921+
Tcl_Interp *childInterp,
2922+
Tcl_Obj *varNameObj,
2923+
Tcl_Obj *valueObj)
2924+
{
2925+
int result = TCL_ERROR;
2926+
Tcl_Obj *resultObj;
2927+
Tcl_Preserve(childInterp);
2928+
2929+
// Modelled after the guts of Tcl_SetObjCmd().
2930+
if (valueObj) {
2931+
resultObj = Tcl_ObjSetVar2(childInterp, varNameObj, NULL, valueObj,
2932+
TCL_LEAVE_ERR_MSG);
2933+
} else {
2934+
resultObj = Tcl_ObjGetVar2(childInterp, varNameObj, NULL,
2935+
TCL_LEAVE_ERR_MSG);
2936+
}
2937+
if (resultObj) {
2938+
Tcl_SetObjResult(childInterp, resultObj);
2939+
result = TCL_OK;
2940+
}
2941+
2942+
Tcl_TransferResult(childInterp, result, interp);
2943+
Tcl_Release(childInterp);
2944+
return result;
2945+
}
2946+
28812947
/*
28822948
*----------------------------------------------------------------------
28832949
*

library/package.tcl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -348,17 +348,17 @@ proc pkg_mkIndex {args} {
348348
$c eval [list ::tcl::DiscoverPackageContents $dir $file $direct]
349349
} on error msg {
350350
if {$doVerbose} {
351-
set what [$c eval set ::tcl::debug]
351+
set what [$c set ::tcl::debug]
352352
tclLog "warning: error while $what $file: $msg"
353353
}
354354
} on ok {} {
355355
if {$doVerbose} {
356-
set what [$c eval set ::tcl::debug]
356+
set what [$c set ::tcl::debug]
357357
tclLog "successful $what of $file"
358358
}
359-
set type [$c eval set ::tcl::type]
360-
set cmds [lsort [dict keys [$c eval set ::tcl::newCmds]]]
361-
set pkgs [$c eval set ::tcl::newPkgs]
359+
set type [$c set ::tcl::type]
360+
set cmds [lsort [dict keys [$c set ::tcl::newCmds]]]
361+
set pkgs [$c set ::tcl::newPkgs]
362362
if {$doVerbose} {
363363
if {!$direct} {
364364
tclLog "commands provided were $cmds"

library/safe.tcl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ proc ::safe::InterpSetConfig {child access_path staticsok nestedok deletehook au
428428
lappend tokens_auto_path [dict get $remap_access_path $dir]
429429
}
430430
}
431-
::interp eval $child [list set auto_path $tokens_auto_path]
431+
::interp set $child auto_path $tokens_auto_path
432432

433433
# Add the tcl::tm directories to the access path.
434434
set morepaths [::tcl::tm::list]
@@ -767,7 +767,7 @@ proc ::safe::SyncAccessPath {child} {
767767

768768
set child_access_path $state(access_path,child)
769769
if {$AutoPathSync} {
770-
::interp eval $child [list set auto_path $child_access_path]
770+
::interp set $child auto_path $child_access_path
771771

772772
Log $child "auto_path in $child has been set to $child_access_path"\
773773
NOTICE
@@ -777,8 +777,7 @@ proc ::safe::SyncAccessPath {child} {
777777
# list of access path's. See -> InterpSetConfig for the code which
778778
# ensures this condition.
779779

780-
::interp eval $child [list \
781-
set tcl_library [lindex $child_access_path 0]]
780+
::interp set $child tcl_library [lindex $child_access_path 0]
782781
return
783782
}
784783

0 commit comments

Comments
 (0)