############################################################################### # # listing.tk - Routines to handle the program listing system # # Copyright (c) 1993,1994,1995,1996 # Bradford W. Mott # November 13,1993 ############################################################################### # $Id: listing.tk,v 1.1 1996/08/02 14:56:55 bwmott Exp $ ############################################################################### ############################################################################### # Called to (re)initialize the program listing system ############################################################################### proc ProgramListing:Initialize {} { global ProgramListing global ProgramListingAddressTable ## Remove the Address Table array if it exists catch {unset ProgramListingAddressTable} ## Initialize all of the globals set ProgramListing(Filename) "" set ProgramListing(Contents) "" set ProgramListing(ContentsChanged) 1 set ProgramListing(FindString) "" ## Refresh myself ProgramListing:Refresh } ############################################################################### # Refresh the listing ############################################################################### proc ProgramListing:Refresh {} { global ProgramListing global ProgramListingAddressTable ## Make sure the program listing window exists if {[winfo exists .programListing] == 0} {return} ## See if we need to refresh the contents of the text widget if {$ProgramListing(ContentsChanged) == 1} { ## Update the text widgets contents ProgramListing:RefreshContents ## Update the title displayed by the window manager if {$ProgramListing(Filename) != ""} { wm title .programListing \ "BSVC: Program Listing - [file tail $ProgramListing(Filename)]" } else { wm title .programListing "BSVC: Program Listing" } ## Update the breakpoint tags ProgramListing:RefreshBreakpoints ## Tell tk to go ahead an re-display everything update idletasks } ## Make sure a simulator is running if {[GetApplicationMode] == "StartupMode"} {return} ## Get the Program Counter's value PutLine "ProgramCounterValue" scan [lindex [GetList] 0] "%x" pc ## Remove tag from old lines .programListing.pack.text tag remove PCTag 1.0 end catch { ## Highlight each of the lines eval ".programListing.pack.text tag add PCTag \ $ProgramListingAddressTable($pc)" ## Move the view to the last highlighted line .programListing.pack.text see PCTag.last } } ############################################################################### # Refresh the contents of the text widget ############################################################################### proc ProgramListing:RefreshContents {} { global ProgramListing ## Indicate that the contents have not changed (since we're updating them) set ProgramListing(ContentsChanged) 0 ## Put the text window in normal mode so we can delete and insert info .programListing.pack.text configure -state normal ## Empty text widget .programListing.pack.text delete 1.0 end ## Insert the program listing contents into the text widget foreach line $ProgramListing(Contents) { .programListing.pack.text insert end [format "%-128s\n" $line] } ## Disable the text window so no editing can occur .programListing.pack.text configure -state disabled } ############################################################################### # Apply the breakpoint tag to every line which has a breakpoint set on it ############################################################################### proc ProgramListing:RefreshBreakpoints {} { global ProgramListing global ProgramListingAddressTable ## Make sure a simulator is running before we try anything if {[GetApplicationMode] == "StartupMode"} {return} ## Update breakpoint highlighting .programListing.pack.text tag remove BreakpointTag 1.0 end ## Get a list of all of the breakpoints and highlight the ## lines which correspond to them PutLine "ListBreakpoints" foreach breakpoint [GetList] { ## Get the decimal value of the breakpoint scan $breakpoint "%x" value catch { eval ".programListing.pack.text tag add BreakpointTag \ $ProgramListingAddressTable($value)" } } } ############################################################################### # Using the given filename see if a listing file exists with one of the # "standard" extensions (removes any extension from name before trying) ############################################################################### proc ProgramListing:SetFilename {name} { global ProgramListing ## Set of standard program listing extensions set fileEndings {.l .lis .list .L .Lis .List .LIS .LIST \ .lst .Lst .LST .Listing .listing} ## Initialize filename to nothing set ProgramListing(Filename) "" ## See if a listing file exists for the given program foreach i $fileEndings { set listingFile [file rootname $name]$i if {[file exists $listingFile] == 1} { set ProgramListing(Filename) $listingFile break; } } ## Load the new listing file ProgramListing:Load } ############################################################################### # Allow the user to load a file of their choice ############################################################################### proc ProgramListing:ManualLoad {} { global ProgramListing ## Get the filename set name [Tool:OpenFileSelector -title "Select file to load:" \ -parent .programListing] if {$name !=""} { if {[file isdirectory $name]} { Tool:AlertDialog .programListing \ "ERROR: The specified file is a directory!" } elseif {[file exists $name]} { set ProgramListing(Filename) $name ProgramListing:Load } else { Tool:AlertDialog .programListing \ "ERROR: The specified file does not exists!" } } } ############################################################################### # Load program listing file specified by ProgramListing(Filename) ############################################################################### proc ProgramListing:Load {} { global ProgramListing global ProgramListingAddressTable ## Remove the Address Table array catch {unset ProgramListingAddressTable} ## Empty the program listing contents set ProgramListing(Contents) "" ## Indicate that the contents have changed set ProgramListing(ContentsChanged) 1 ## Make sure there's really a file to load if {$ProgramListing(Filename) != ""} { ## Open the file or return if we can't if {[catch {set file [open $ProgramListing(Filename)]}] != 0} { set ProgramListing(Filename) "" ProgramListing:Refresh return } ## Load the program listing contents set ProgramListing(Contents) [split [read $file] "\n"] close $file ## Calculate the address to line number table set lineNumber 1 foreach line $ProgramListing(Contents) { if {[regexp {^[0-9a-fA-F]+} $line] == 1} { scan $line "%x" address append ProgramListingAddressTable($address) \ "$lineNumber.0 \"$lineNumber.0 lineend + 1 char\" " incr lineNumber } else { incr lineNumber } } } ProgramListing:Refresh } ############################################################################### # Prompt user for a string to find and highlight the first occurance if found ############################################################################### proc ProgramListing:Find {} { global ProgramListing ## Ask user for search pattern set input [Tool:EntryDialog .programListing \ "Enter pattern to search for:" {.+}] ## Make sure something was entered if {$input == ""} {return} set ProgramListing(FindString) $input ## Find the first thing that matches the pattern set index [.programListing.pack.text search -count length \ -forwards -nocase -regexp -- $ProgramListing(FindString) 1.0] ## See if there was a match if {$index != ""} { .programListing.pack.text tag remove SearchTag 1.0 end .programListing.pack.text tag add SearchTag \ "$index" "$index + $length char" .programListing.pack.text see \ [.programListing.pack.text index "SearchTag.last linestart"] update idletasks .programListing.pack.text see \ [.programListing.pack.text index "SearchTag.last"] ## Turn on find again .programListing.menubar.edit.menu entryconfigure "Find Again " \ -state normal bind .programListing {ProgramListing:FindAgain; break} } else { set ProgramListing(FindString) "" Tool:AlertDialog .programListing "No matches were found!" } } ############################################################################### # Highlight the next occurance of FindString if found ############################################################################### proc ProgramListing:FindAgain {} { global ProgramListing ## Find the place to start the search if {[.programListing.pack.text tag nextrange SearchTag 1.0 end] == ""} { set current 1.0 } else { set current [.programListing.pack.text index "SearchTag.last + 1 char"] } ## Remove old tags .programListing.pack.text tag remove SearchTag 1.0 end ## Search for new match set index [.programListing.pack.text search -count length \ -forwards -nocase -regexp -- $ProgramListing(FindString) $current] ## See if we were able to find a match if {$index != ""} { .programListing.pack.text tag add SearchTag \ "$index" "$index + $length char" .programListing.pack.text see \ [.programListing.pack.text index "SearchTag.last linestart"] update idletasks .programListing.pack.text see \ [.programListing.pack.text index "SearchTag.last"] } } ############################################################################### # Remove all of the breakpoints that are currently set ############################################################################### proc ProgramListing:ClearBreakpoints {} { ## Tell the simulator to list the breakpoints PutLine "ListBreakpoints" ## Tell the simulator to delete each of the breakpoints foreach i [GetList] { PutLine "DeleteBreakpoint $i" GetList } ## Refresh the breakpoint tags ProgramListing:RefreshBreakpoints } ############################################################################### # Toggle breakpoint state for the address in the line at coordinate (x,y) ############################################################################### proc ProgramListing:ToggleBreakpoint {x y} { global ProgramListing global ProgramListingAddressTable ## Get the line where the mouse button was pressed set line [.programListing.pack.text get "@$x,$y linestart" "@$x,$y lineend"] ## See if a hexadecimal address is the first element on the line if {[regexp {^[0-9a-fA-F]+} $line] == 1} { scan $line "%x" address set address [format "%x" $address] ## Should we be adding or removing if {[lsearch -exact [.programListing.pack.text tag names "@$x,$y"] \ BreakpointTag] == -1} { ## Tell the simulator to add the breakpoint PutLine "AddBreakpoint $address" GetList } else { ## Tell the simulator to delete the breakpoint PutLine "DeleteBreakpoint $address" GetList } ## Refresh the breakpoint tags ProgramListing:RefreshBreakpoints } } ############################################################################### # Set widgets to the correct application mode ############################################################################### proc ProgramListing:SetApplicationMode {mode} { global ProgramListing ## Return if the program listing window does not exist if {[winfo exists .programListing] == 0} {return} ## The program listing can always be closed bind .programListing {ProgramListing:Close; break} ## Handle "Find Again" option if {$ProgramListing(FindString) != "" && $mode == "SimulationMode"} { .programListing.menubar.edit.menu entryconfigure "Find Again " \ -state normal bind .programListing {ProgramListing:FindAgain; break} } else { .programListing.menubar.edit.menu entryconfigure "Find Again " \ -state disabled bind .programListing {break} } ## Handle other options if {$mode == "SimulationMode"} { .programListing.menubar.file.menu entryconfigure "Load... " -state normal .programListing.menubar.edit.menu entryconfigure "Find... " -state normal .programListing.menubar.edit.menu entryconfigure "Clear Breakpoints " \ -state normal bind .programListing {ProgramListing:Find; break} bind .programListing {ProgramListing:ManualLoad; break} bind .programListing.pack.text \ {ProgramListing:ToggleBreakpoint %x %y} } elseif {$mode == "StartupMode"} { ## Reinitialize the program listing system ProgramListing:Initialize .programListing.menubar.file.menu entryconfigure "Load... " \ -state disabled .programListing.menubar.edit.menu entryconfigure "Find... " \ -state disabled .programListing.menubar.edit.menu entryconfigure "Clear Breakpoints " \ -state disabled bind .programListing {break} bind .programListing {break} bind .programListing.pack.text "break" } else { ## ModalMode and RunningMode .programListing.menubar.file.menu entryconfigure "Load... " \ -state disabled .programListing.menubar.edit.menu entryconfigure "Find... " \ -state disabled .programListing.menubar.edit.menu entryconfigure "Clear Breakpoints " \ -state disabled bind .programListing {break} bind .programListing {break} bind .programListing.pack.text "break" } } ############################################################################### # Display the program listing window ############################################################################### proc ProgramListing:Open {} { global Program global ProgramListing ## Make sure the program listing window does not already exist if {[winfo exists .programListing] == 1} { ## It exists so deiconify it wm deiconify .programListing return } ## Create the top level window toplevel .programListing wm iconname .programListing "Program Listing" wm iconbitmap .programListing "@$Program(BitmapDir)/listicon.xbm" wm minsize .programListing 80 14 ## Create the menu bar frame .programListing.menubar -relief raised -borderwidth 2 menubutton .programListing.menubar.file -text "File" \ -menu .programListing.menubar.file.menu menu .programListing.menubar.file.menu -tearoff 0 .programListing.menubar.file.menu add command \ -label "Load... " -accelerator "Ctrl-L" \ -command {ProgramListing:ManualLoad} .programListing.menubar.file.menu add separator .programListing.menubar.file.menu add command \ -label "Close " -accelerator "Ctrl-W" \ -command {ProgramListing:Close} menubutton .programListing.menubar.edit -text "Edit" \ -menu .programListing.menubar.edit.menu menu .programListing.menubar.edit.menu -tearoff 0 .programListing.menubar.edit.menu add command \ -label "Find... " -accelerator "Ctrl-F" \ -command {ProgramListing:Find} .programListing.menubar.edit.menu add command \ -label "Find Again " -accelerator "Ctrl-G" \ -command {ProgramListing:FindAgain} .programListing.menubar.edit.menu add separator .programListing.menubar.edit.menu add command \ -label "Clear Breakpoints " \ -command {ProgramListing:ClearBreakpoints} pack .programListing.menubar.file -side left pack .programListing.menubar.edit -side left ## Create the text widget to display the program listing in frame .programListing.pack text .programListing.pack.text -relief sunken \ -cursor left_ptr -wrap none \ -yscrollcommand ".programListing.pack.yscroll set" \ -xscrollcommand ".programListing.pack.xscroll set" \ -setgrid 1 -state disabled \ -takefocus 0 -highlightthickness 0 if {[winfo depth .programListing.pack.text] > 1} { .programListing.pack.text tag configure PCTag \ -foreground Black -background SkyBlue -relief raised -borderwidth 1 .programListing.pack.text tag configure BreakpointTag -foreground #ff0000 .programListing.pack.text tag configure SearchTag \ -background #ce5555 -foreground white } else { .programListing.pack.text tag configure PCTag \ -foreground White -background Black .programListing.pack.text tag configure BreakpointTag -font 6x13bold .programListing.pack.text tag configure SearchTag -underline 1 } bind .programListing.pack.text "break" bind .programListing.pack.text "break" bind .programListing.pack.text "break" bind .programListing.pack.text "break" bind .programListing.pack.text "break" bind .programListing.pack.text "break" ## Create scroll bars for text window scrollbar .programListing.pack.yscroll -relief sunken \ -takefocus 0 -highlightthickness 0 \ -command ".programListing.pack.text yview" scrollbar .programListing.pack.xscroll -relief sunken \ -takefocus 0 -highlightthickness 0 \ -orient horizontal \ -command ".programListing.pack.text xview" pack .programListing.pack.xscroll -side bottom -fill x pack .programListing.pack.yscroll -side left -fill y pack .programListing.pack.text -side left -fill both -expand 1 pack .programListing.menubar -side top -fill x pack .programListing.pack -side top -fill both -expand 1 -padx 2 ## Indicate that there is no find string yet set ProgramListing(FindString) "" ## Configure all of the widgets to their correct state ProgramListing:SetApplicationMode [GetApplicationMode] ## Indicate that the contents need to be refreshed set ProgramListing(ContentsChanged) 1 ## Refresh the program listing ProgramListing:Refresh } ############################################################################### # Close the program listing window ############################################################################### proc ProgramListing:Close {} { catch {destroy .programListing} } ## Go ahead an initialize program listing system upon loading ProgramListing:Initialize