#****************************************************************************** #*** #*** This file is part of XTeXShell; see file xtexsh for details #*** Version 0.91 (21.2.94) #*** #****************************************************************************** #****************************************************************************** #*** Execute Programs in a TCL window ***************************************** #****************************************************************************** proc ExecProg {command} { #*** #*** Execute command. Command may include the symbol :fname, which #*** will be replaced by the filname of the file loaded in the editor #*** or, if specified, by the main filename. :fnamewoext will be replaced #*** by filename without extension. #*** If fname == "", use mainname or editfname without extension #*** Before executing, change to directory of fname #*** global editfname editwin global mainflag mainname global readchild readchierr writechild global childpid global boldl_font global chisaveflag chireloadflag global critsect #*** Is there another programm running ? if {![info exist critsect]} {set critsect 0} if {[childstat] || $critsect} { DisplayInfo "Sorry:\nThere is another program running\n\nKill other program first" "$boldl_font" return } set critsect 1 #*** Determine fname as explained above set fname "" if {[info exists editfname]} { set fname $editfname } if {$mainflag} {set fname $mainname} #*** Replace macros :save :reload :fname :fnamewoext set chisaveflag false set chireloadflag false set filenameneeded 0 while {1} { set pos [string first ":" "$command"] if {$pos==-1} {break} set sstr [expr {$pos ? [crange "$command" 0 "$pos-1" ] : ""}] set estr [crange "$command" "$pos+1" end] set mstr [string tolower [ctoken estr " .,:"]] if {[cequal "$mstr" "fnamewoext"]} { set mstr [strip_extension $fname] set filenameneeded 1 } if {[cequal "$mstr" "fname"]} { set mstr $fname set filenameneeded 1 } if {[cequal "$mstr" "save"]} { set mstr "" set chisaveflag true } if {[cequal "$mstr" "reload"]} { set mstr "" set chireloadflag true } set command [format "%s%s%s" "$sstr" "$mstr" "$estr"] } #*** Does the command need a file name? If yes, check if we have a valid filename if {$filenameneeded && [cequal "" $fname]} { if {[info exists editwin] && [winfo exists $editwin]} { DisplayInfo "Please save your file before executing this command.\n I don't know the name of your file yet" $boldl_font } else { DisplayInfo "No File has been specified so far.\nCannot execute command!\nPlease load a file in the editor or specify a main file!" $boldl_font } set critsect 0 return } #*** Create window if it doesn't exist global exec_win execwin_name execwin_geo set exec_win $execwin_name set c $execwin_name.c if {[cequal "" [CreateTopWin execwin ""]]} { wm withdraw $exec_win wm deiconify $exec_win } else { wm title $exec_win "$command" wm iconname $exec_win "$command" frame $exec_win.but -relief raised -borderwidth 1 -width 80c -height 10c pack $exec_win.but -side bottom -fill x button $exec_win.but.kill -text "Kill Program" -command {childkill} button $exec_win.but.done -text "Done" -command {childkill; destroy $exec_win} button $exec_win.but.clear -text "Clear" -command {$exec_win.c delete 0.0 end} pack $exec_win.but.kill $exec_win.but.clear -side left -anchor s -fill x -padx 3m -pady 1m -ipadx 0.6m pack $exec_win.but.done -side right -anchor s -fill x -padx 3m -pady 1m -ipadx 0.6m scrollbar $exec_win.ys -command "$c yview" -relief sunken pack $exec_win.ys -side right -fill y text $c -relief raised -bd 2 -yscrollcommand "$exec_win.ys set" pack $c -side left -fill both -expand yes $c tag configure error -foreground red $c tag configure message -foreground blue bind $c { %W insert insert "\n" puts $writechild "" %W yview -pickplace insert } bind $c { if {[childstat]} { %W insert insert %A puts -nonewline $writechild "%A" %W yview -pickplace insert } } bind $c <1> { focus %W} bind $c <2> {%W scan mark -%y} bind $c {%W scan dragto -%y} } #*** Save text ? global editor if {$chisaveflag} { if {[cequal "$editor" "xtex"] && [Qmodflag]} {SaveFile ""} } #*** Compose Command, program-name should go to prog, parameters to command eval set command \"$command\" set progname [lvarpop command 0] set childpath [string range $fname 0 [string last "/" $fname]] #*** Create pipes to enable communication with child pipe readchild writepar; #*** Child --> Parent fcntl $readchild NONBLOCK 1 fcntl $readchild NOBUF 1 pipe readchierr writeparerr; #*** Child stderr --> Parent fcntl $readchierr NONBLOCK 1 fcntl $readchierr NOBUF 1 pipe readpar writechild; #*** Parent --> Child fcntl $writechild NOBUF 1 #*** Now fork and start program InsertWithTags $c "Executing: $progname $command\n\n" message focus $c update if {[set childpid [fork]] == 0} { dup $readpar stdin; #*** Child process, set IO to pipes close $readpar dup $writepar stdout close $writepar dup $writeparerr stderr close $writeparerr pushd $childpath; #*** Change to data file directory execl $progname $command puts stderr "*** Sorry: Programm could not be started" kill [id process] exit 255 } #*** Disable buffering and install driver to update window 5x per second set critsect 0 after 250 {childIO $childpid} } proc childkill {} { #*** Kill the child process global childpid if {[childstat]} { kill 9 $childpid } } proc childstat {} { #*** Get status of child. (0 = child does not exist) #*** If child exists: Read stdout and stderr from child and append to the #*** variables chistdout and chistderr. #*** Then check status of child with the wait function and write return value #*** to chistatus. Return 0 if wait returns end of process condition. global childpid chireloadflag global childpid readchild readchierr writechild global exec_win if {![info exists childpid]} {set childpid 0; return 0} if {!$childpid} {return 0} #*** Read Standard-Error and Standard-Output from child and write it on exec-window set pmode [lindex [select [list $readchierr $readchild] {} {} 0] 0] if {[winfo exists $exec_win.c]} { if {[string first $readchierr $pmode] >=0 } { InsertWithTags $exec_win.c [read $readchierr] error $exec_win.c yview -pickplace insert } if {[string first $readchild $pmode] >=0 } { InsertWithTags $exec_win.c [read $readchild] "" $exec_win.c yview -pickplace insert } } #*** Check Status of child set chistatus [wait -nohang $childpid] if {$childpid != [lindex $chistatus 0]} { return 1 } else { #*** Process has terminated. Tell user close $readchild close $readchierr close $writechild if {[cequal "EXIT" [lindex $chistatus 1]]} { set msg [format "\nProgram terminated, ERC: %d" [lindex $chistatus 2]] } else { set msg [format "\n\nProgram was killed by signal: %s" [lindex $chistatus 2]] } if {[winfo exists $exec_win.c]} { InsertWithTags $exec_win.c "$msg\n" message InsertWithTags $exec_win.c "----------------------------------------------------------------------------\n" "" $exec_win.c yview -pickplace insert } global editor if {$chireloadflag} { if {[cequal $editor "xtex"]} { ReLoadFile } } set childpid 0 } } proc childIO {reqchipid} { #*** This process runs in background during execution of a unix command #*** It calls childstat which updates the exec window and restarts itself #*** after a delay of 200ms global childpid if {[childstat]==1 && $reqchipid==$childpid} { after 200 childIO $reqchipid } }