#--------------------------------------------------------------------------- # # adp_compile -- # # Parameters: # sourcetype -source|-filename # source # Returns: # Code to generate templated output # #--------------------------------------------------------------------------- proc adp_compile {sourcetype source} { # process parameters switch -exact -- $sourcetype { -source { set contents $source } -filename { set fileid [open $source r] set contents [read $fileid] close $fileid } default { return } } # really simple logic. # 1. look for <% %> # 2. dump out contents preceeding <% # 3. script contents preceeding %> # 4. repeat until run out of <% %> pairs # 5. dump contents after the last %> found. set outbuf {} set position 0 set pstart [string first <% $contents $position] set pend [string first %> $contents $pstart] while {[expr $pstart != -1 && $pend != -1 && $pstart < $pend]} { # Prevent script from adding unexpected blank lines to output: # if script is on a stand-alone line then # don't add a newline to output set last_newline [string last \n $contents $pstart] zdebug "position=$position last_newline=$last_newline pstart=$pstart pend=$pend" if {[expr $last_newline != -1]} { set first_chars [string range $contents $last_newline [expr $pstart-1]] set last_char [string index $contents [expr $pend + 2]] if {[string equal $last_char \n] && [string is space $first_chars]} { # # Replace <% %> tags with spaces # set contents [string replace $contents $pstart [expr $pstart + 1] { }] set contents [string replace $contents $pend [expr $pend + 1] { }] set pstart $last_newline+1 incr pend } } # dump out contents preceeding <% adp_dump [string range $contents $position [expr $pstart-1]] # script out contents within the <% %> adp_script [string range $contents [expr $pstart+2] [expr $pend-1]] # if the next character is \n chomp it #if {[string equal [string index $contents [expr $pend + 2]] \n]} { # incr pend 1 #} # search again set position [expr $pend + 2] set pstart [string first <% $contents $position] set pend [string first %> $contents $pstart] } # dump out contents after %> adp_dump [string range $contents [expr $position] end] # insert pre and post conditions set precond "set __adp_output {}\n" set postcond "" set final "" append final $precond append final $outbuf append final $postcond return $final } #--------------------------------------------------------------------------- # # adp_dump -- # # Remarks: # generate code to output text to the output buffer # #--------------------------------------------------------------------------- proc adp_dump { text } { upvar outbuf outbuf # Protect double quotes, dollar signs, escapes regsub -all {[\]\[""\\$]} $text {\\&} quoted append outbuf "append __adp_output \"$quoted\"" } #--------------------------------------------------------------------------- # # adp_eval -- # # Parameters: # sourcetype -source|-filename # source # # Returns: # Templated output # #--------------------------------------------------------------------------- proc adp_eval { sourcetype source } { set code [adp_compile $sourcetype $source] return [eval $code] } #--------------------------------------------------------------------------- # # adp_script -- # # Remarks: # if <%= > tag, print the contents # else, dumps as tcl source # #--------------------------------------------------------------------------- proc adp_script { script } { # Protect double quotes, dollar signs, escapes # regsub -all {[\]\[""\\$]} $text {\\&} quoted upvar outbuf outbuf if {[string equal [string index $script 0] =]} { # # first character is equal sign: # handle the remainder as an expression # append outbuf "\n" set script [string range $script 1 end] append outbuf "append __adp_output $script" append outbuf "\n" } else { append outbuf "\n" append outbuf " $script" append outbuf "\n" } } proc zdebug text { #puts $text } #--------------------------------------------------------------------------- # # test -- # # Remarks: # demonstration # #--------------------------------------------------------------------------- proc test {} { # If you have testhello.adp in current directory # set code [adp_compile -filename testhello.adp] set source [testprepare] set code [adp_compile -source $source] puts "--------------------------------------------" puts "The source" puts "--------------------------------------------" puts $source puts "--------------------------------------------" puts "The code generated" puts "--------------------------------------------" puts $code puts "--------------------------------------------" puts "The result" puts "--------------------------------------------" eval $code puts $__adp_output } proc testprepare {} { return "

Hello World

<% set name \"Peter\" %> Hello <%=\$name%>
Goodbye <%=\$name%> <% set mylist \[list Tom Dick Harry\] foreach name \$mylist {%>

Welcome <%=\$name%>

<% }%> log off " } # 1. Straight test -- # test # 2. Test for incorporation into subroutine # set source [testprepare] # set code [adp_compile -source $source] # return [eval $code]