From: pmarin on
Hi all.

I want to send a list to a program and to capture the output.
currently I am using a 'chan pipe' whith 'exec'. Is it the correct
way? How can I do the same using 'open "| ..."'

The piece of code:

proc dmenu_run {} {
if {[uptodate]} {
set str "exec dmenu $::argv < $::CACHE"
catch {exec [{*}$str] }
} else {
set pipe [chan pipe]
foreach f [generate_cache] {
puts [lindex $pipe 1] $f
}
close [lindex $pipe 1]
set str "exec dmenu $::argv <@[lindex $pipe 0]"
catch {exec [{*}$str] }
close [lindex $pipe 0]
}
}
From: Alexandre Ferrieux on
On Mar 29, 8:18 pm, pmarin <pacog...(a)gmail.com> wrote:
> Hi all.
>
> I want to send a list to a program and to capture the output.
> currently I am using a  'chan pipe' whith 'exec'. Is it the correct
> way? How can I do the same using 'open "| ..."'
>
> The piece of code:
>
> [...]
>       set pipe [chan pipe]
>       foreach f [generate_cache] {
>          puts [lindex $pipe 1] $f
>       }
>       close [lindex $pipe 1]
>       set str "exec dmenu $::argv <@[lindex $pipe 0]"
>       catch {exec [{*}$str] }
>       close [lindex $pipe 0]

This code is problematic because it may deadlock if [generate_cache]'s
output doesn't fit in the pipe's buffer (since you must have written
everything before spawning the child process).

Here are several ways:

(1)
set res [exec dmenu {*}$::argv << [join [generate_cache] \n]]

(2)
set f [open "|dmenu $::argv 2>@ stderr" r+]
puts $f [join [generate_cache] \n]
close $f w
set res [read $f]
close $f

(3)
foreach {pr pw} [chan pipe] break
set f [open "|dmenu $::argv <@ $pr 2>@ stderr" r]
close $pr
puts $pw [join [generate_cache] \n]
close $pw
set res [read $f]
close $f

-Alex
From: pmarin on
On Mar 29, 9:03 pm, Alexandre Ferrieux <alexandre.ferri...(a)gmail.com>
wrote:
> On Mar 29, 8:18 pm, pmarin <pacog...(a)gmail.com> wrote:
>
>
>
> > Hi all.
>
> > I want to send a list to a program and to capture the output.
> > currently I am using a  'chan pipe' whith 'exec'. Is it the correct
> > way? How can I do the same using 'open "| ..."'
>
> > The piece of code:
>
> > [...]
> >       set pipe [chan pipe]
> >       foreach f [generate_cache] {
> >          puts [lindex $pipe 1] $f
> >       }
> >       close [lindex $pipe 1]
> >       set str "exec dmenu $::argv <@[lindex $pipe 0]"
> >       catch {exec [{*}$str] }
> >       close [lindex $pipe 0]
>
> This code is problematic because it may deadlock if [generate_cache]'s
> output doesn't fit in the pipe's buffer (since you must have written
> everything before spawning the child process).
>
> Here are several ways:
>
>  (1)
>     set res [exec dmenu {*}$::argv << [join [generate_cache] \n]]
>
>  (2)
>     set f [open "|dmenu $::argv 2>@ stderr" r+]
>     puts $f  [join [generate_cache] \n]
>     close $f w
>     set res [read $f]
>     close $f
>
>  (3)
>     foreach {pr pw} [chan pipe] break
>     set f [open "|dmenu $::argv <@ $pr 2>@ stderr" r]
>     close $pr
>     puts $pw [join [generate_cache] \n]
>     close $pw
>     set res [read $f]
>     close $f
>
> -Alex

I always forget the 'join' command.
Thank you!