| | @@ -439,12 +439,12 @@ |
| 439 | 439 | |
| 440 | 440 | /* |
| 441 | 441 | ** TH1 command: tclEval arg ?arg ...? |
| 442 | 442 | ** |
| 443 | 443 | ** Evaluates the Tcl script and returns its result verbatim. If a Tcl script |
| 444 | | -** error is generated, it will be transformed into a TH1 script error. A Tcl |
| 445 | | -** interpreter will be created automatically if it has not been already. |
| 444 | +** error is generated, it will be transformed into a TH1 script error. The |
| 445 | +** Tcl interpreter will be created automatically if it has not been already. |
| 446 | 446 | */ |
| 447 | 447 | static int tclEval_command( |
| 448 | 448 | Th_Interp *interp, |
| 449 | 449 | void *ctx, |
| 450 | 450 | int argc, |
| | @@ -498,11 +498,12 @@ |
| 498 | 498 | /* |
| 499 | 499 | ** TH1 command: tclExpr arg ?arg ...? |
| 500 | 500 | ** |
| 501 | 501 | ** Evaluates the Tcl expression and returns its result verbatim. If a Tcl |
| 502 | 502 | ** script error is generated, it will be transformed into a TH1 script error. |
| 503 | | -** A Tcl interpreter will be created automatically if it has not been already. |
| 503 | +** The Tcl interpreter will be created automatically if it has not been |
| 504 | +** already. |
| 504 | 505 | */ |
| 505 | 506 | static int tclExpr_command( |
| 506 | 507 | Th_Interp *interp, |
| 507 | 508 | void *ctx, |
| 508 | 509 | int argc, |
| | @@ -563,12 +564,12 @@ |
| 563 | 564 | |
| 564 | 565 | /* |
| 565 | 566 | ** TH1 command: tclInvoke command ?arg ...? |
| 566 | 567 | ** |
| 567 | 568 | ** Invokes the Tcl command using the supplied arguments. No additional |
| 568 | | -** substitutions are performed on the arguments. A Tcl interpreter will |
| 569 | | -** be created automatically if it has not been already. |
| 569 | +** substitutions are performed on the arguments. The Tcl interpreter |
| 570 | +** will be created automatically if it has not been already. |
| 570 | 571 | */ |
| 571 | 572 | static int tclInvoke_command( |
| 572 | 573 | Th_Interp *interp, |
| 573 | 574 | void *ctx, |
| 574 | 575 | int argc, |
| | @@ -633,10 +634,100 @@ |
| 633 | 634 | Tcl_Release((ClientData)tclInterp); |
| 634 | 635 | rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, |
| 635 | 636 | getTh1ReturnCode(rc)); |
| 636 | 637 | return rc; |
| 637 | 638 | } |
| 639 | + |
| 640 | +/* |
| 641 | +** TH1 command: tclIsSafe |
| 642 | +** |
| 643 | +** Returns non-zero if the Tcl interpreter is "safe". The Tcl interpreter |
| 644 | +** will be created automatically if it has not been already. |
| 645 | +*/ |
| 646 | +static int tclIsSafe_command( |
| 647 | + Th_Interp *interp, |
| 648 | + void *ctx, |
| 649 | + int argc, |
| 650 | + const char **argv, |
| 651 | + int *argl |
| 652 | +){ |
| 653 | + Tcl_Interp *tclInterp; |
| 654 | + |
| 655 | + if( createTclInterp(interp, ctx)!=TH_OK ){ |
| 656 | + return TH_ERROR; |
| 657 | + } |
| 658 | + if( argc!=1 ){ |
| 659 | + return Th_WrongNumArgs(interp, "tclIsSafe"); |
| 660 | + } |
| 661 | + tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 662 | + if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 663 | + Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 664 | + return TH_ERROR; |
| 665 | + } |
| 666 | + Th_SetResultInt(interp, Tcl_IsSafe(tclInterp)); |
| 667 | + return TH_OK; |
| 668 | +} |
| 669 | + |
| 670 | +/* |
| 671 | +** TH1 command: tclMakeSafe |
| 672 | +** |
| 673 | +** Forces the Tcl interpreter into "safe" mode by removing all "unsafe" |
| 674 | +** commands and variables. This operation cannot be undone. The Tcl |
| 675 | +** interpreter will remain "safe" until the process terminates. |
| 676 | +*/ |
| 677 | +static int tclMakeSafe_command( |
| 678 | + Th_Interp *interp, |
| 679 | + void *ctx, |
| 680 | + int argc, |
| 681 | + const char **argv, |
| 682 | + int *argl |
| 683 | +){ |
| 684 | + static int registerChans = 1; |
| 685 | + Tcl_Interp *tclInterp; |
| 686 | + int rc = TH_OK; |
| 687 | + |
| 688 | + if( createTclInterp(interp, ctx)!=TH_OK ){ |
| 689 | + return TH_ERROR; |
| 690 | + } |
| 691 | + if( argc!=1 ){ |
| 692 | + return Th_WrongNumArgs(interp, "tclMakeSafe"); |
| 693 | + } |
| 694 | + tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 695 | + if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 696 | + Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 697 | + return TH_ERROR; |
| 698 | + } |
| 699 | + if( Tcl_IsSafe(tclInterp) ){ |
| 700 | + Th_ErrorMessage(interp, |
| 701 | + "Tcl interpreter is already 'safe'", (const char *)"", 0); |
| 702 | + return TH_ERROR; |
| 703 | + } |
| 704 | + if( registerChans ){ |
| 705 | + /* |
| 706 | + ** HACK: Prevent the call to Tcl_MakeSafe() from actually closing the |
| 707 | + ** standard channels instead of simply unregistering them from |
| 708 | + ** the Tcl interpreter. This should only need to be done once |
| 709 | + ** per thread (process?). |
| 710 | + */ |
| 711 | + registerChans = 0; |
| 712 | + Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDIN)); |
| 713 | + Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDOUT)); |
| 714 | + Tcl_RegisterChannel(NULL, Tcl_GetStdChannel(TCL_STDERR)); |
| 715 | + } |
| 716 | + Tcl_Preserve((ClientData)tclInterp); |
| 717 | + if( Tcl_MakeSafe(tclInterp)!=TCL_OK ){ |
| 718 | + int nResult; |
| 719 | + const char *zResult = getTclResult(tclInterp, &nResult); |
| 720 | + Th_ErrorMessage(interp, |
| 721 | + "could not make Tcl interpreter 'safe':", zResult, nResult); |
| 722 | + rc = TH_ERROR; |
| 723 | + }else{ |
| 724 | + Th_SetResult(interp, 0, 0); |
| 725 | + } |
| 726 | + Tcl_Release((ClientData)tclInterp); |
| 727 | + return rc; |
| 728 | +} |
| 638 | 729 | |
| 639 | 730 | /* |
| 640 | 731 | ** Tcl command: th1Eval arg |
| 641 | 732 | ** |
| 642 | 733 | ** Evaluates the TH1 script and returns its result verbatim. If a TH1 script |
| | @@ -709,13 +800,15 @@ |
| 709 | 800 | static struct _Command { |
| 710 | 801 | const char *zName; |
| 711 | 802 | Th_CommandProc xProc; |
| 712 | 803 | void *pContext; |
| 713 | 804 | } aCommand[] = { |
| 714 | | - {"tclEval", tclEval_command, 0}, |
| 715 | | - {"tclExpr", tclExpr_command, 0}, |
| 716 | | - {"tclInvoke", tclInvoke_command, 0}, |
| 805 | + {"tclEval", tclEval_command, 0}, |
| 806 | + {"tclExpr", tclExpr_command, 0}, |
| 807 | + {"tclInvoke", tclInvoke_command, 0}, |
| 808 | + {"tclIsSafe", tclIsSafe_command, 0}, |
| 809 | + {"tclMakeSafe", tclMakeSafe_command, 0}, |
| 717 | 810 | {0, 0, 0} |
| 718 | 811 | }; |
| 719 | 812 | |
| 720 | 813 | /* |
| 721 | 814 | ** Called if the Tcl interpreter is deleted. Removes the Tcl integration |
| 722 | 815 | |