
proc get_commands {fd} {
    upvar #0 get_commands_buffer($fd) buf

    if {![info exists buf]} {set buf ""}
    set data [read $fd]

    if {$data == ""} {
	error "EOF: $fd"
    }
    set buf "$buf$data"
    set commands [split $buf "\n"]
    set n_commands [llength $commands]
    if {$n_commands <= 1} {return ""}

    set buf [lindex $commands end]
    set commands [lrange $commands 0 [expr $n_commands-2]]
    return $commands
}

proc eval_commands {fd} {
    set commands [get_commands $fd]
    set errors ""

    foreach cmd $commands {
	if {[catch {uplevel #0 $cmd} status] != 0} {
	    lappend errors $status
	}
    }
    foreach error $errors {
	puts "Read Command Error: $error"
    }
}

proc puts_retry {fd message} {
    global errorCode

    set error EAGAIN
    while {$error == "EAGAIN"} {
	if {[catch {puts $fd $message} retval] != 0} {
	    set error [lindex $errorCode 1]
	} else {
	    set error ""
	}
    }
    if {$error != ""} {
	error $retval
    } else {
	return $retval
    }
}

proc pipe_exec {args} {
    pipe local remote
    dup $remote file61
    close $remote
    set remote file61

    fcntl $local NONBLOCK 1
    fcntl $remote NONBLOCK 1
    fileevent $local readable "eval_commands $local"

    regsub file $remote {} remotefd

    if {[catch \
	   {eval exec $args -pipe $remotefd &} status] != 0} {
	close $local
	close $remote
	error $status
    }
    close $remote
    return $local
}
