Visual Studio 2003 .sln file parser

I needed to find the web projects in a specific Microsoft Visual Studio 2003 solution (.sln) file. Here's how I did it...


 ### Script to clear Visual Studio's web cache for projects in a given solution file.

 variable VS2K3VersionString "Microsoft Visual Studio Solution File, Format Version 8.00"

 # We need the uri package to parse the project URLs
 package require uri

 proc find_projects {sln_body} {
         # Returns a list containing the projects in the solution.  Each list item is itself a list: 
         # element 0 is the project name, element 1 is the location for the project
         variable VS2K3VersionString  
         set projects_out [list]

         if {[string first $VS2K3VersionString $sln_body] != 0} {
                 error "This doesn't appear to be a VS2003 solution file.  I don't know what to do with it."
         }
         set sln_body [string range $sln_body [string length $VS2K3VersionString] end]

         # An arbitrary unicode character used to mark the end of projects so we can split the projects
         set arbitrary_unicode_char \u9999

         set sln_body [string map [list {EndProjectSection} {EndProjectSection} {EndProject} "EndProject${arbitrary_unicode_char}"] $sln_body]

         # Split the sln_body into projects and drop all the non-project stuff at the end of the .sln
         # This assumes that projects are always at the beginning of the .sln file.
         # We also assume that there is non-project stuff in the .sln following the projects - 
         # lrange trims off everything after the last project
         set projects [lrange [split $sln_body $arbitrary_unicode_char] 0 end-1]
 
         foreach p $projects {
                 set p [string trim $p]
                 set temp [string range $p [expr {[string first "=" $p]+1}] end]
                 foreach {name location} [split $temp ","] {break}
 
                 set name [string trim [string map [list {"} {}] $name]]
                 set location [string trim [string map [list {"} {}] $location]]
 
                 lappend projects_out [list $name $location]
         }
 
         return $projects_out
 }
 
 proc find_web_projects {sln_body} {
 # Returns just the web projects in a solution
         set projects_out [list]
         set plist [find_projects $sln_body]
 
         foreach project $plist {
                 foreach {name location} $project {break}
 
                 if {[string match "http://*" $location]} {
                         lappend projects_out $project
                 }
         }
 
         return $projects_out
 
 }

 proc clear_web_cache {sln_body cache_dir} {
         foreach project [find_web_projects $sln_body] {
                 foreach {name url} $project {break}
 
                 array set url_arr [uri::split $url]
                
                 if {[string equal "localhost" $url_arr(host)]} {
                         set url_arr(host) [info hostname]
                 }
                 set url_arr(host) [string toupper $url_arr(host)]

                 set path_to_delete [file join $cache_dir $url_arr(host) [file dirname $url_arr(path)]]

                 if {[file exists $path_to_delete] && [file isdirectory $path_to_delete]} {
                         file delete -force $path_to_delete
                         puts "Deleted cache directory $path_to_delete"
                 }
         }
 }

 # Usage sample: 
 set fd [open SomeSolution.sln r]
 set sln_body [read $fd]
 close $fd
 clear_web_cache $sln_body [file join $env(USERPROFILE) VSWebCache]

-- Joseph Anderson