• quoting difficulty

    From et4@21:1/5 to All on Sat Sep 24 17:34:30 2022
    I have a text entry where I want to be able to enter an arbitrary command to execute at global level with both the input command and the result written out using puts. The string to execute is sent as an arg to a procedure.

    I've tried several methods, using [after 0] and also [uplevel #0] and I'm stumped. I've resorted to trial and error hoping it would eventually work without success.

    Any ideas?

    In my tests, arg is

    $foobar + 5

    and foobar is global and 10, I want to have it output the result: 15


    Here are several attempts, to no avail:


    % set foobar 10
    10

    ------------------------
    % proc test {arg} {
    uplevel #0 [list puts "result of $arg is\n [list eval $arg]"]
    }
    % test {$foobar + 5}
    result of $foobar + 5 is
    eval {$foobar + 5}

    ------------------------


    % proc test {arg} {
    uplevel #0 [list puts "result of $arg is\n [eval $arg]"]
    }
    % test {$foobar + 5}
    can't read "foobar": no such variable

    ------------------------


    % proc test {arg} {
    uplevel #0 [list puts "result of $arg is\n [$arg]"]
    }
    % test {$foobar + 5}
    invalid command name "$foobar + 5"

    --------------------------

    % proc test {arg} {
    uplevel #0 [list puts "result of $arg is\n \[list $arg\]"]
    }
    % test {$foobar + 5}
    result of $foobar + 5 is
    [list $foobar + 5]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et4@21:1/5 to All on Sat Sep 24 17:41:44 2022
    On 9/24/2022 5:34 PM, et4 wrote:
    I have a text entry where I want to be able to enter an arbitrary command to execute at global level with both the input command and the result written out using puts. The string to execute is sent as an arg to a procedure.

    I've tried several methods, using [after 0] and also [uplevel #0] and I'm stumped. I've resorted to trial and error hoping it would eventually work without success.

    Any ideas?

    In my tests, arg is

    $foobar + 5

    and foobar is global and 10, I want to have it output the result: 15


    Here are several attempts, to no avail:


    % set foobar 10
    10

    ------------------------
    % proc test {arg} {
         uplevel #0 [list puts "result of $arg is\n [list eval $arg]"]
     }
    % test {$foobar + 5}
    result of $foobar + 5 is
     eval {$foobar + 5}

    ------------------------


    % proc test {arg} {
        uplevel #0 [list puts "result of $arg is\n [eval $arg]"]
    }
    % test {$foobar + 5}
    can't read "foobar": no such variable

    ------------------------


    % proc test {arg} {
        uplevel #0 [list puts "result of $arg is\n [$arg]"]
    }
    % test {$foobar + 5}
    invalid command name "$foobar + 5"

    --------------------------

    % proc test {arg} {
        uplevel #0 [list puts "result of $arg is\n \[list $arg\]"]
    }
     % test {$foobar + 5}
    result of $foobar + 5 is
     [list $foobar + 5]



    In all these tests, I should have been trying:


    test {expr $foobar + 5}


    but it doesn't seem to work with all my attempts

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ya Hu@21:1/5 to All on Sat Sep 24 18:29:06 2022
    воскресенье, 25 сентября 2022 г. в 03:41:49 UTC+3, et4:
    On 9/24/2022 5:34 PM, et4 wrote:
    I have a text entry where I want to be able to enter an arbitrary command to execute at global level with both the input command and the result written out using puts. The string to execute is sent as an arg to a procedure.

    I've tried several methods, using [after 0] and also [uplevel #0] and I'm stumped. I've resorted to trial and error hoping it would eventually work without success.

    Any ideas?

    In my tests, arg is

    $foobar + 5

    and foobar is global and 10, I want to have it output the result: 15


    Here are several attempts, to no avail:


    % set foobar 10
    10

    ------------------------
    % proc test {arg} {
    uplevel #0 [list puts "result of $arg is\n [list eval $arg]"]
    }
    % test {$foobar + 5}
    result of $foobar + 5 is
    eval {$foobar + 5}

    ------------------------


    % proc test {arg} {
    uplevel #0 [list puts "result of $arg is\n [eval $arg]"]
    }
    % test {$foobar + 5}
    can't read "foobar": no such variable

    ------------------------


    % proc test {arg} {
    uplevel #0 [list puts "result of $arg is\n [$arg]"]
    }
    % test {$foobar + 5}
    invalid command name "$foobar + 5"

    --------------------------

    % proc test {arg} {
    uplevel #0 [list puts "result of $arg is\n \[list $arg\]"]
    }
    % test {$foobar + 5}
    result of $foobar + 5 is
    [list $foobar + 5]
    In all these tests, I should have been trying:


    test {expr $foobar + 5}


    but it doesn't seem to work with all my attempts

    proc t a {
    set res [uplevel 1 expr [list $a]]
    puts "result of \$arg is $res" ;
    return $res
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to [email protected] on Sun Sep 25 02:17:55 2022
    et4 <[email protected]> wrote:
    On 9/24/2022 5:34 PM, et4 wrote:
    I have a text entry where I want to be able to enter an arbitrary
    command to execute at global level with both the input command and
    the result written out using puts. The string to execute is sent as
    an arg to a procedure.

    I've tried several methods, using [after 0] and also [uplevel #0]
    and I'm stumped. I've resorted to trial and error hoping it would
    eventually work without success.

    Any ideas?

    In my tests, arg is

    $foobar + 5

    and foobar is global and 10, I want to have it output the result: 15


    In all these tests, I should have been trying:

    test {expr $foobar + 5}

    but it doesn't seem to work with all my attempts

    $ rlwrap tclsh
    % proc test {args} {
    uplevel #0 eval {*}$args
    }
    % set foobar 10
    10
    % test {expr $foobar + 5}
    15
    %

    But, note, you are currently walking down a path that will eventually
    lead to you directly to "quoting hell" (https://wiki.tcl-lang.org/page/Quoting+hell).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et4@21:1/5 to Rich on Sat Sep 24 21:01:10 2022
    On 9/24/2022 7:17 PM, Rich wrote:
    et4 <[email protected]> wrote:
    On 9/24/2022 5:34 PM, et4 wrote:
    I have a text entry where I want to be able to enter an arbitrary
    command to execute at global level with both the input command and
    the result written out using puts. The string to execute is sent as
    an arg to a procedure.

    I've tried several methods, using [after 0] and also [uplevel #0]
    and I'm stumped. I've resorted to trial and error hoping it would
    eventually work without success.

    Any ideas?

    In my tests, arg is

    $foobar + 5

    and foobar is global and 10, I want to have it output the result: 15


    In all these tests, I should have been trying:

    test {expr $foobar + 5}

    but it doesn't seem to work with all my attempts

    $ rlwrap tclsh
    % proc test {args} {
    uplevel #0 eval {*}$args
    }
    % set foobar 10
    10
    % test {expr $foobar + 5}
    15
    %

    But, note, you are currently walking down a path that will eventually
    lead to you directly to "quoting hell" (https://wiki.tcl-lang.org/page/Quoting+hell).

    Thanks Rich.

    I see what you mean, I think I'm already there:

    % proc test {args} {
    uplevel #0 eval {*}$args
    }

    % test {puts hello}
    hello

    % test {puts "hello there"}
    can not find channel named "hello"

    % test {puts \"hello there\"}
    hello there

    % test {set foo "bar baz"}
    wrong # args: should be "set varName ?newValue?"

    (kits) 23 % test {set foo "bar"}
    bar


    This has to be do-able, since the windows console and linux interactive mode can run any arbitrary commands. I even tried a thread::send back to the main thread to see if that would work, and couldn't get to go.

    I couldn't figure out how to use Ya Hu's since it only uses expr, which was only just one example. I need it to do any command, it's supposed to be like a one-line console from a text entry.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to All on Sun Sep 25 00:13:02 2022
    On 9/24/22 8:34 PM, et4 wrote:
    I have a text entry where I want to be able to enter an arbitrary
    command to execute at global level with both the input command and the
    result written out using puts. The string to execute is sent as an arg
    to a procedure.

    I've tried several methods, using [after 0] and also [uplevel #0] and
    I'm stumped. I've resorted to trial and error hoping it would eventually
    work without success.

    Any ideas?

    In my tests, arg is

    $foobar + 5

    and foobar is global and 10, I want to have it output the result: 15

    Since you are passing full commands, how about this:

    % proc test x {uplevel #0 $x}


    Note that for math expressions, you will need to put them in [expr]
    properly.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sun Sep 25 04:23:43 2022
    I believe this is what you want:

    proc xx {args} {
    set x [uplevel #0 $args]
    puts "Command: $args"
    puts "Result: $x"
    return $x
    }

    Normally the script argument to uplevel is a list to avoid "quoting hell".
    In this case $args is already a list. Do not expand it using {*}.

    Dave B

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et4@21:1/5 to [email protected] on Sat Sep 24 23:27:13 2022
    On 9/24/2022 9:23 PM, [email protected] wrote:
    I believe this is what you want:

    proc xx {args} {
    set x [uplevel #0 $args]
    puts "Command: $args"
    puts "Result: $x"
    return $x
    }

    Normally the script argument to uplevel is a list to avoid "quoting hell".
    In this case $args is already a list. Do not expand it using {*}.

    Dave B


    ahhhhh, nice, this is working with every twisted attempt to break it :)

    In my actual case (not the test code posted), I have several text entry widgets and what I am actually given is $w which is the widget that had <return> entered. So, I ended up with this,

    set var [$w cget -textvariable] ;# name of the variable, not the value
    set val [set $var] ;# get the actual value
    puts "result for \u3010 $val \u3011 "
    if [catch {
    set res [uplevel #0 $val]
    } err_code] {
    puts $err_code
    return
    }
    puts "\u3010$res\u3011"


    And here is one such result (hope the unicode formats here):


    result for 【 set xyz [list 1 2 3 4 5 {more here} "check { it } out [list [pwd] two]" ] 】
    【1 2 3 4 5 {more here} {check { it } out {A:/New folder} two}】


    Thanks so much Dave!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to [email protected] on Sun Sep 25 12:35:32 2022
    et4 <[email protected]> wrote:
    On 9/24/2022 7:17 PM, Rich wrote:
    et4 <[email protected]> wrote:
    On 9/24/2022 5:34 PM, et4 wrote:
    I have a text entry where I want to be able to enter an arbitrary
    command to execute at global level with both the input command and
    the result written out using puts. The string to execute is sent as
    an arg to a procedure.

    This has to be do-able, since the windows console and linux
    interactive mode can run any arbitrary commands.

    When building commands, use [list]. You should almost always use [list]
    for building up commands.

    Plus, with an entry (or other Tk widget) you don't have the problem of
    the Tcl code parser also 'interpreting' the code, before your eval
    thereof, which is what starts to generate quoting hell situations.

    I.e.:

    #!/usr/bin/wish

    entry .e
    button .b -text run -command [list button-pushed .e]
    pack .e .b -side top

    proc button-pushed {w} {
    set cmd [$w get]
    set result [run $cmd]
    puts result=$result
    $w delete 0 end
    }

    proc run {cmd} {
    return [uplevel #0 [list eval $cmd]]
    }

    set foo 10

    Then, putting this into the entry and pressing the 'run' button gives:

    puts "hello foo + 5 = [expr {$foo+5}]"

    this result in my rxvt window:

    hello foo + 5 = 15
    result=

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et4@21:1/5 to Rich on Sun Sep 25 10:35:26 2022
    On 9/25/2022 5:35 AM, Rich wrote:
    et4 <[email protected]> wrote:
    On 9/24/2022 7:17 PM, Rich wrote:
    et4 <[email protected]> wrote:
    On 9/24/2022 5:34 PM, et4 wrote:
    I have a text entry where I want to be able to enter an arbitrary
    command to execute at global level with both the input command and
    the result written out using puts. The string to execute is sent as >>>>> an arg to a procedure.

    This has to be do-able, since the windows console and linux
    interactive mode can run any arbitrary commands.

    When building commands, use [list]. You should almost always use [list]
    for building up commands.

    Plus, with an entry (or other Tk widget) you don't have the problem of
    the Tcl code parser also 'interpreting' the code, before your eval
    thereof, which is what starts to generate quoting hell situations.

    I.e.:

    #!/usr/bin/wish

    entry .e
    button .b -text run -command [list button-pushed .e]
    pack .e .b -side top

    proc button-pushed {w} {
    set cmd [$w get]
    set result [run $cmd]
    puts result=$result
    $w delete 0 end
    }

    proc run {cmd} {
    return [uplevel #0 [list eval $cmd]]
    }

    set foo 10

    Then, putting this into the entry and pressing the 'run' button gives:

    puts "hello foo + 5 = [expr {$foo+5}]"

    this result in my rxvt window:

    hello foo + 5 = 15
    result=


    Thanks Rich. Your example is now in my tips/tricks scrap book. Generally I do go to [list] but couldn't get the rest to work.

    I've got another entry where I need to go uplevel inside a proc that issued a call to me (as a breakpoint). I'll try out your code there, though I will need to use a different uplevel. I also have an up/down/mousewheel history for the text entry and a
    button to repeat the last command. So, I can get the text to execute from several places.

    BTW, I've got you to thank for the indirection I'm using to get the value of the textvariable (set val [set $var]) from a post of yours a year or two back.

    Here's what I get now with your test case:

    result for 【 set foo 10 】
    【10】

    result for 【 puts "hello foo + 5 = [expr {$foo+5}]" 】
    hello foo + 5 = 15
    【】

    result for 【 puts "hello foo + 5 = [expr {$fooxx+5}]" 】
    can't read "fooxx": no such variable

    result for 【 puts "hello foo + 5 = [exprxxx {$foo+5}]" 】
    invalid command name "exprxxx"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Luc@21:1/5 to All on Sun Sep 25 17:19:59 2022
    I don't understand the many suggestions of using [list] and upvar.

    I have this code that works just fine:

    entry $::w.frame0.aliasbox
    $::w.frame0.aliasbox configure -takefocus 1
    $::w.frame0.aliasbox configure -width $::ALIASWIDTH
    $::w.frame0.aliasbox configure -background $::ALIASBG
    $::w.frame0.aliasbox configure -foreground $::ALIASFG
    $::w.frame0.aliasbox configure -textvariable ::INPUT

    later on,

    eval {*}$::INPUT

    Note that $::INPUT may be an alias that will be resolved
    by an external list... or a proc (also defined externally),
    which seems to be what you want.

    I never needed upvar and [list] definitely does not work
    for me because it causes the entire proc and arguments
    to be treated like a single block of text, as if
    proc arguments were "proc arguments".


    --
    Luc

    **************************
    On Sun, 25 Sep 2022 10:35:26 -0700, et4 wrote:

    On 9/25/2022 5:35 AM, Rich wrote:
    et4 <[email protected]> wrote:
    On 9/24/2022 7:17 PM, Rich wrote:
    et4 <[email protected]> wrote:
    On 9/24/2022 5:34 PM, et4 wrote:
    I have a text entry where I want to be able to enter an
    arbitrary command to execute at global level with both the
    input command and the result written out using puts. The
    string to execute is sent as an arg to a procedure.

    This has to be do-able, since the windows console and linux
    interactive mode can run any arbitrary commands.

    When building commands, use [list]. You should almost always use
    [list] for building up commands.

    Plus, with an entry (or other Tk widget) you don't have the problem
    of the Tcl code parser also 'interpreting' the code, before your
    eval thereof, which is what starts to generate quoting hell

  • From et4@21:1/5 to Luc on Sun Sep 25 14:21:11 2022
    On 9/25/2022 1:19 PM, Luc wrote:
    I don't understand the many suggestions of using [list] and upvar.

    I have this code that works just fine:

    entry $::w.frame0.aliasbox
    $::w.frame0.aliasbox configure -takefocus 1
    $::w.frame0.aliasbox configure -width $::ALIASWIDTH
    $::w.frame0.aliasbox configure -background $::ALIASBG
    $::w.frame0.aliasbox configure -foreground $::ALIASFG
    $::w.frame0.aliasbox configure -textvariable ::INPUT

    later on,

    eval {*}$::INPUT

    Note that $::INPUT may be an alias that will be resolved
    by an external list... or a proc (also defined externally),
    which seems to be what you want.

    I never needed upvar and [list] definitely does not work
    for me because it causes the entire proc and arguments
    to be treated like a single block of text, as if
    proc arguments were "proc arguments".



    But where is your eval running, i.e. is it at global level or from within a proc, or even a proc called by another a proc?

    In my case with this posting I wanted it to run in global context, hence the uplevel #0. An after 0 would also run in global context.

    In my other case, I need uplevel 1 to access locals in the proc that called me. The text entry lets me run any command at all inside the waiting proc.

    With both uplevel and after, there's generally some tricky quoting stuff needed, and often [list] is the right approach. But even then, it can still be tricky, as this thread has shown.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Mon Sep 26 10:18:42 2022
    * Rich <[email protected]d>
    | return [uplevel #0 [list eval $cmd]]

    Since [uplevel] does an eval on it's own, wouldn't

    return [uplevel #0 $cmd]

    be the same?

    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Ralf Fassel on Mon Sep 26 20:15:56 2022
    Ralf Fassel <[email protected]> wrote:
    * Rich <[email protected]d>
    | return [uplevel #0 [list eval $cmd]]

    Since [uplevel] does an eval on it's own, wouldn't

    return [uplevel #0 $cmd]

    be the same?

    Yeah, it would. No need for wrapping in 'list' in that case.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)