proc cvs_usercmd {args} {
#
# Run a cvs command from the user menu.
#
  global cvs

  gen_log:log C "$cvs $args"
  exec_command "CVS $args" "$cvs $args"
}

proc cvs_execcmd {args} {
#
# Run any command form the user menu.
#
  gen_log:log C "$args"
  eval "exec $args &"
}

proc cvs_catchcmd {args} {
#
# Run a shell command from the user menu and view its output.
#
  gen_log:log C "$args"
  catch {eval "exec $args"} view_this
  view_output [lindex $args 0] $view_this
}

#
# Set up a dialog containing a text box to view
# the report of the command during execution.
#
proc exec_command_init {title} {
  global exec_win

  static {exec_viewer 0}
  set my_idx $exec_viewer
  incr exec_viewer

  set exec_win($my_idx,lines) 0
  set exec_win($my_idx,win) ".exec$my_idx"
  set exec_win($my_idx,text) ".exec$my_idx.text"
  set exec_win($my_idx,scroll) ".exec$my_idx.scroll"
  set exec_win($my_idx,ok) ".exec$my_idx.ok"
  set exec_win($my_idx,destroyed) 0

  toplevel $exec_win($my_idx,win)
  text $exec_win($my_idx,text) -setgrid yes -relief sunken -border 2 \
      -exportselection 1 \
      -yscroll "$exec_win($my_idx,scroll) set"
  scrollbar $exec_win($my_idx,scroll) -relief sunken \
      -command "$exec_win($my_idx,text) yview"
  button $exec_win($my_idx,ok) -text "Stop" \
      -command "stop_command 0 $my_idx" -state disabled
  pack $exec_win($my_idx,ok) -side bottom -fill x
  pack $exec_win($my_idx,scroll) -side right -fill y
  pack $exec_win($my_idx,text) -fill both -expand 1
  # Focus to activate text bindings
  focus $exec_win($my_idx,win)
  wm title $exec_win($my_idx,win) "$title"
  return $my_idx
}

proc exec_command_body { my_idx command } {
  global exec_win
  global cvscfg

  if {$command == ""} {
    cvsfail "Nothing to execute."
  } else {
    if {[catch {open "| $command |& cat"} exec_win($my_idx,log)]} {
      $exec_win($my_idx,text) insert end $exec_win($my_idx,log)\n
      exec_command_end $my_idx
    } else {                    
      set exec_win($my_idx,run) 1
      fileevent $exec_win($my_idx,log) readable "ins_exec_log_line $my_idx"
      if { $cvscfg(allow_abort) == "yes" } {
        $exec_win($my_idx,ok) configure -state normal
      } else {
        $exec_win($my_idx,ok) configure -state normal \
            -text "Please wait..." -command ""
      }
      tkwait variable exec_win($my_idx,run)
    }
  }
  update idletasks
}

proc exec_command_end { my_idx } {
  global exec_win

  if { $exec_win($my_idx,destroyed) == 0 } {
        $exec_win($my_idx,ok) configure -text "Please wait..." -command ""
    update idletasks
    $exec_win($my_idx,ok) configure -text "Ok" -command "stop_command 1 $my_idx"
  }
}

proc exec_command {title command args} {
  global exec_win

  set my_idx [exec_command_init $title]
  set exec_win($my_idx,lines) 0
  exec_command_body $my_idx $command
  if {[llength $args] == 2} {
     set arg1 [lindex $args 0]
     set arg2 [lindex $args 1]
     if {$arg1 == 0} {
       # append if text empty
       if {$exec_win($my_idx,lines) == 0} {
         $exec_win($my_idx,text) insert end "$arg2\n"
       }
     } else {
       if {$arg1 == 1} {
        # always append
        $exec_win($my_idx,text) insert end "$arg2\n"
      }
    }
  }
  exec_command_end $my_idx
}

proc ins_exec_log_line { my_idx } {
  global exec_win
  global cvscfg
    
  if {[eof $exec_win($my_idx,log)]} {
    catch {close $exec_win($my_idx,log)}
    # do some thing at end of program
    if { [info exists cvscfg(exec_eof)] } {
      if { $cvscfg(exec_eof) != "" } {
        set line [eval $cvscfg(exec_eof)]
        if { $line!="" } {
          $exec_win($my_idx,text) insert end $line
          $exec_win($my_idx,text) see end
          incr exec_win($my_idx,lines)
        }
      }
    }
    set exec_win($my_idx,run) 0
  } else {
    gets $exec_win($my_idx,log) line
    #gen_log:log D "$line"
    $exec_win($my_idx,text) insert end $line\n
    $exec_win($my_idx,text) see end
    if {$line!=""} {
      incr exec_win($my_idx,lines)
    }
  }
  update idletasks
}

proc stop_command {force my_idx } {
  global exec_win

  set mess "Really quit command?"
  if { $force == 1 || [tk_dialog .message {Confirm!} $mess warning 0 NO YES]} {
    catch {close $exec_win($my_idx,log)}
    if { $exec_win($my_idx,destroyed) == 0 } {
      set exec_win($my_idx,destroyed) 1
      destroy $exec_win($my_idx,win)
    }
  }
  update idletasks
}

proc view_output {title output_string} {
#
# Set up a dialog containing a text box that can be used to view
# the report on the screen.
#
  global cvscfg
  global cvsglb
  static {viewer 0}

  gen_log:log T "ENTER ($title <output_string suppressed>)"
  # Initialize searching
  search_textwidget_init

  # If nothing to report, then say so.
  if {$output_string == ""} {
    set mess "Nothing to report."
    cvsok $mess
    return
  }
  incr viewer
  set cvsview ".cvsview$viewer"
  toplevel $cvsview

  frame $cvsview.bottom
  button $cvsview.bottom.ok -text "Close" \
    -command "destroy $cvsview"
  button $cvsview.bottom.srchbtn -text Search \
    -command "search_textwidget $cvsview.text"
  entry $cvsview.bottom.entry -width 20 -textvariable cvsglb(searchstr)
  bind $cvsview.bottom.entry <Return> \
    "search_textwidget $cvsview.text"

  pack $cvsview.bottom -side bottom -fill x
  pack $cvsview.bottom.srchbtn -side left
  pack $cvsview.bottom.entry -side left
  pack $cvsview.bottom.ok -side right -ipadx 15

  text $cvsview.text -setgrid yes -relief sunken -border 2 \
    -exportselection 1 \
    -yscroll "$cvsview.scroll set"
  scrollbar $cvsview.scroll -relief sunken \
    -command "$cvsview.text yview"

  pack $cvsview.scroll -side right -fill y
  pack $cvsview.text -fill both -expand 1

  wm title $cvsview "$title Output"
  $cvsview.text insert end $output_string
  # Focus in the text widget to activate the text bindings
  $cvsview.text configure -state disabled
  focus $cvsview.text

  gen_log:log T "LEAVE"
}

