Mat's Playground

Mat's Playground

Description

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)
the old main page the old repository the old web lab


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).

Download

Source code

Hide line numbers Expand lines
  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 {\&quot;} 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 &quot;$val&quot;"
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 {\&amp;} text
294                regsub -all {<} $text {\&lt;} text
295                regsub -all {>} $text {\&gt;} 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