| main | console | Legend - Hand of God | web | contact |
| music browser | playground |
The playground.cgi was the name-sake for this web-site and the script that drove the old version of it. Basically it provided global header and footer parts, created the navigation menu on-the-fly and read the actual pages' content from seperate files.
In short, it mimiced the SSI technology, while allowing the use of Tcl commands inside HTML documents.
The main purpose of the playground script was to format my shell scripts on the fly.
Here are some screenshots (click for a larger version)
I strongly doubt someone will use this, but perhaps you can get some inspiration from that script, so I'll go on describing it anyway:
First have a look at the needed directory tree of the server:
When opening the URL in a browser, playground.cgi creates the basic layout of the page, creates the menu below the title bar from all existing files under texts/ and displays the appropriate text file between the header and footer of the page.
The text files contain normal html, everything which is normally between <body></body> (minus header and footer).
1#!/bin/sh 2# the next line restarts using tclsh \ 3exec tclsh "$0" "$@" 4 5 6# config variables 7set config(TEXTS_PATH) [file join $env(DOCUMENT_ROOT) "playground/texts"] 8set config(IMAGES_PATH) [file join $env(DOCUMENT_ROOT) "playground/images"] 9set config(SCRIPTS_PATH) [file join $env(DOCUMENT_ROOT) "playground/scripts"] 10set config(CSS_FILE) [file join $env(DOCUMENT_ROOT) "playground/style.css"] 11 12 13# display all environment variables 14proc show_env {} { 15 global env 16 puts "<pre>" 17 foreach i [parray env] {puts $i} 18 puts "</pre>" 19} 20 21# global header 22proc header {{currentPage ""} {description ""}} { 23 puts "Content-type: text/html\n" 24 puts "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">" 25 puts "<html>" 26 puts " <head>" 27 puts " <meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">" 28 if {$description != ""} then { 29 puts " <meta name=\"description\" content=\"$description\">" 30 } 31 puts " <meta name=\"author\" content=\"Mat\">" 32 puts " <link rel=\"stylesheet\" type=\"text/css\" href=\"/?css\">" 33 puts " <title>Mat's Playground</title>" 34 puts " </head>" 35 puts " <body>" 36 puts "" 37 puts " <table class=\"window\">" 38 if {$currentPage != "script_following"} then { 39 puts " <tr>" 40 puts " <td style=\"height:31px;\"></td>" 41 puts " </tr>" 42 } 43 puts " <tr>" 44 puts " <td align=\"center\">" 45 puts " <div class=\"window\">" 46 47 if {$currentPage != "script_following"} then { 48 puts " <div class=\"window-title\">Mat's Playground</div>" 49 menu $currentPage 50 puts " <div class=\"window-content\">" 51 } else { 52 puts " <div class=\"script\">" 53 } 54 55 puts " <!-- CONTENT -->\n" 56} 57 58 59# global menu 60proc menu {currentPage} { 61 global config env 62 63 set availPages [lsort -dictionary [glob -nocomplain [file join $config(TEXTS_PATH) "*"]]] 64 65 # site "main" is to be set at the beginning, site "contact" at the end 66 set main [file join $config(TEXTS_PATH) "main"] 67 set contact [file join $config(TEXTS_PATH) "contact"] 68 69 set pos [lsearch $availPages $main] 70 set availPages [lreplace $availPages $pos $pos] 71 72 set pos [lsearch $availPages $contact] 73 set availPages [lreplace $availPages $pos $pos] 74 75 set availPages [concat $main $availPages $contact] 76 unset main contact pos 77 78 puts " <div class=\"menu\">" 79 puts " |" 80 81 foreach page $availPages { 82 set page [file rootname [file tail $page]] 83 84 # don't display underscores 85 regsub -all "_" $page " " title 86 87 88 89 if {[string match $page $currentPage]} then { 90 set page "$title" 91 } else { 92 set page [makeLink "/?show=$page" $title] 93 } 94 95 puts " <span>$page</span>" 96 puts " |" 97 unset page title 98 } 99 100 puts " </div>" 101 102 unset availPages 103} 104 105# global footer 106proc footer {{currentPage ""}} { 107 puts " <!-- CONTENT -->" 108 puts " </div>" 109 puts " </div>" 110 puts " <div class=\"sig\">" 111 puts " created by [makeImg "mat.png" "Mat"]" 112 puts " </div>" 113 puts " </td>" 114 puts " </tr>" 115 116 if {$currentPage != "script_following"} then { 117 puts " <tr>" 118 puts " <td style=\"text-align: right; height: 31px;\">" 119 puts " [makeLink "http://validator.w3.org/check?uri=referer" [makeImg "valid-html40.png" "Valid HTML 4.0"]]" 120 puts " [makeLink "http://jigsaw.w3.org/css-validator/check/referer" [makeImg "valid-css.png" "Valid CSS"]]" 121 puts " </td>" 122 puts " </tr>" 123 } 124 125 puts " </table>" 126 puts " </body>" 127 puts "</html>" 128} 129 130# inserts an image 131proc makeImg {img {title ""}} { 132 return "<img src=\"/?image=$img\" alt=\"$title\" title=\"$title\">" 133} 134 135# inserts a link 136proc makeLink {href desc {title ""}} { 137 if {$title == "" && [string range $desc 1 3] != "img"} then { 138 set title $desc 139 } 140 141 return "<a href=\"$href\" title=\"$title\">$desc</a>" 142} 143 144# inserts a link to a scriptfile 145proc scriptLink {mode file {title ""}} { 146 if {$mode == "view"} then { 147 if {$title == ""} then { 148 set title "view $file" 149 } 150 return "<a onClick=\"javascript:window.open('/?view=$file','$file','height=530,width=860,scrollbars=yes');return false\" href=\"/?view=$file\" title=\"$title\">view</a>" 151 } else { 152 if {$title == ""} then { 153 set title "download $file" 154 } 155 return "<a href=\"/?dl=$file\" title=\"$title\">download</a> (use right-click to save)" 156 } 157} 158 159 160 161 162# 163# let the site begin 164# 165 166catch { 167 168 set query $env(QUERY_STRING) 169 170 if {$query == ""} then { 171 puts "Location: $env(SCRIPT_NAME)?show=main\n\n" 172 } 173 174 # a query is of the form 'command=value', here it is separated 175 set cmd [lindex [split $query "="] 0] 176 set val [join [lrange [split $query "="] 1 end] "="] 177 178 # avoid exploitations 179 set val [file tail $val] 180 181 switch $cmd { 182 "show" { 183 # 184 # display html stuff 185 # 186 set file [file join $config(TEXTS_PATH) "$val"] 187 188 if {![file exists $file]} then { 189 header $val 190 puts "No such site \"$val\"" 191 footer 192 } else { 193 # open the file 194 set fd [open $file r] 195 196 # get first line 197 set first [gets $fd] 198 199 # get rest of text 200 set text [read $fd] 201 202 # close the file 203 close $fd 204 unset fd 205 206 # first line may contain a meta-description 207 if {[string range $first 0 11] == "DESCRIPTION:"} then { 208 # we have a description 209 set desc [string trim [string range $first 12 end]] 210 regsub -all {"} $desc {\"} desc 211 } else { 212 set desc "" 213 set text [join [list $first $text] \n] 214 } 215 216 # output the header 217 header $val $desc 218 219 # mask special characters 220 regsub -all "\"" $text "\\\"" text 221 222 # change :) into image tags 223 regsub -all ":\\\)" $text "\[makeImg smile.gif :)\]" text 224 225 # display content 226 eval "puts \"$text\"" 227 228 # footer 229 footer 230 231 unset first text desc 232 } 233 unset file 234 } 235 236 "image" { 237 # 238 # returns an image 239 # 240 241 set file [file join $config(IMAGES_PATH) "$val"] 242 243 if {![file exists $file]} then { 244 header 245 puts "No such image \"$val\"" 246 footer 247 } else { 248 set ext [string range [file extension $val] 1 end] 249 if {$ext == "jpg"} then {set ext "jpeg"} 250 251 # read image 252 set img [open $file r] 253 254 # emit image 255 puts "Content-Disposition: filename=$val" 256 puts "Content-type: image/[set ext]\n" 257 258 259 fconfigure $img -translation binary -encoding binary 260 fconfigure stdout -translation binary -encoding binary 261 fcopy $img stdout 262 263 # close image 264 close $img 265 266 unset ext img 267 } 268 unset file 269 } 270 271 "view" { 272 # 273 # displays script 274 # 275 276 header "script_following" "Complete listing of the script "$val"" 277 278 if {$val == "playground.cgi"} then { 279 set file $argv0 280 } else { 281 set file [file join $config(SCRIPTS_PATH) $val] 282 } 283 284 285 if {![file exists $file]} then { 286 puts "No such file \"$val\"" 287 } else { 288 set fd [open $file r] 289 set text [read $fd] 290 close $fd 291 292 # mask html characters 293 regsub -all {&} $text {\&} text 294 regsub -all {<} $text {\<} text 295 regsub -all {>} $text {\>} text 296 297 puts "<div class=\"title\">$val</div>" 298 puts "<pre>" 299 puts "$text" 300 puts "</pre>" 301 302 unset fd text 303 } 304 unset file 305 306 footer "script_following" 307 } 308 309 "dl" { 310 # 311 # returns a script (download) 312 # 313 314 if {$val == "playground.cgi"} then { 315 set file $argv0 316 } else { 317 set file [file join $config(SCRIPTS_PATH) $val] 318 } 319 320 if {![file exists $file]} then { 321 header 322 puts "No such file \"$val\"" 323 footer 324 } else { 325 # read script 326 set fd [open $file r] 327 328 # emit image 329 puts "Content-Disposition: filename=$val" 330 puts "Content-type: text/plain\n" 331 fcopy $fd stdout 332 333 # close script 334 close $fd 335 unset fd 336 } 337 unset file 338 } 339 340 341 css { 342 # 343 # returns our stylesheet 344 # 345 set file $config(CSS_FILE) 346 347 puts "Content-Type: text/css\n" 348 349 set fd [open $file r] 350 set text [read $fd] 351 close $fd 352 353 puts $text 354 355 unset file fd text 356 } 357 358 default { 359 header 360 puts "No such command \"$cmd\"" 361 footer 362 } 363 364 } 365 366 unset query cmd val 367 368} err 369if {$err != ""} then { 370 puts "Content-Type: text/html\n\n" 371 puts "<hr>" 372 puts "<h1>Script Error</h1>" 373 puts "<pre>" 374 puts "$errorInfo" 375 puts "</pre>" 376 puts "<hr>" 377} 378 379array unset config