docstrip.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 package require Tcl 8.4
00018 package provide docstrip 1.2
00019 namespace docstrip {
00020 namespace export extract sourcefrom
00021 }
00022 ret docstrip::extract (type text , type terminals , type args) {
00023 array set O {
00024 -annotate 0
00025 -metaprefix %%
00026 -onerror throw
00027 -trimlines 1
00028 }
00029 array set O $args
00030 foreach t $terminals {set T($t) ""}
00031 set stripped ""
00032 set block_stack [list]
00033 set offlevel 0
00034 set verbatim 0
00035 set lineno 0
00036 foreach line [split $text \n] {
00037 incr lineno
00038 if {$O(-trimlines)} then {
00039 set line [string trimright $line " "]
00040 }
00041 if {$verbatim} then {
00042 if {$line eq $endverbline} then {
00043 set verbatim 0
00044 continue
00045 } elseif {$offlevel} then {
00046 continue
00047 }
00048 append stripped $line \n
00049 if {$O(-annotate)>=1} then {append stripped {V "" ""} \n}
00050 } else {
00051 switch -glob -- $line %%* {
00052 if {!$offlevel} then {
00053 append stripped $O(-metaprefix)\
00054 [string range $line 2 end] \n
00055 if {$O(-annotate)>=1} then {
00056 append stripped [list M %% $O(-metaprefix)] \n
00057 }
00058 }
00059 } %<<* {
00060 set endverbline "%[string range $line 3 end]"
00061 set verbatim 1
00062 continue
00063 } %<* {
00064 if {![
00065 regexp -- {^%<([*/+-]?)([^>]*)>(.*)$} $line ""\
00066 modifier expression line
00067 ]} then {
00068 extract,error BADGUARD\
00069 "Malformed guard \"\n$line\n\""
00070 "Malformed guard on line $lineno"
00071 continue
00072 }
00073 regsub -all -- {\\|\{|\}|\$|\[|\]| |;} $expression\
00074 {\\&} E
00075 regsub -all -- {,} $E {|} E
00076 regsub -all -- {[^()|&!]+} $E {[info exists T(&)]} E
00077 if {[catch {expr $E} val]} then {
00078 extract,error EXPRERR\
00079 "Error in expression <$expression> ignored"\
00080 "docstrip: $val"
00081 set val -1
00082 }
00083 switch -exact -- $modifier * {
00084 lappend block_stack $expression
00085 if {$offlevel || !$val} then {incr offlevel}
00086 continue
00087 } / {
00088 if {![llength $block_stack]} then {
00089 extract,error SPURIOUS\
00090 "Spurious end block </$expression> ignored"\
00091 "Spurious end block </$expression>"
00092 } else {
00093 if {[string compare $expression\
00094 [lindex $block_stack end]]} then {
00095 extract,error MISMATCH\
00096 "Found </$expression> instead of\
00097 </[lindex $block_stack end]>"
00098 }
00099 if {$offlevel} then {incr offlevel -1}
00100 set block_stack [lreplace $block_stack end end]
00101 }
00102 continue
00103 } - {
00104 if {$offlevel || $val} then {continue}
00105 append stripped $line \n
00106 if {$O(-annotate)>=1} then {
00107 append stripped [list - %<-${expression}> ""] \n
00108 }
00109 } default {
00110 if {$offlevel || !$val} then {continue}
00111 append stripped $line \n
00112 if {$O(-annotate)>=1} then {
00113 append stripped\
00114 [list + %<${modifier}${expression}> ""] \n
00115 }
00116 }
00117 } %* {continue}\
00118 {\\endinput} {
00119 break
00120 } default {
00121 if {$offlevel} then {continue}
00122 append stripped $line \n
00123 if {$O(-annotate)>=1} then {append stripped {. "" ""} \n}
00124 }
00125 }
00126 if {$O(-annotate)>=2} then {append stripped $lineno \n}
00127 if {$O(-annotate)>=3} then {append stripped $block_stack \n}
00128 }
00129 return $stripped
00130 }
00131 ret docstrip::extract,error (type situation , type message , optional errmessage ="") {
00132 upvar 1 O(-onerror) onerror lineno lineno
00133 switch -- [string tolower $onerror] "puts" {
00134 puts stderr "docstrip: $message on line $lineno."
00135 } "ignore" {} default {
00136 if {$errmessage ne ""} then {
00137 error $errmessage "" [list DOCSTRIP $situation $lineno]
00138 } else {
00139 error $message "" [list DOCSTRIP $situation $lineno]
00140 }
00141 }
00142 }
00143 ret docstrip::sourcefrom (type name , type terminals , type args) {
00144 set F [open $name r]
00145 if {[llength $args]} then {
00146 eval [linsert $args 0 fconfigure $F]
00147 }
00148 set text [read $F]
00149 close $F
00150 set oldscr [info script]
00151 info script $name
00152 set code [catch {
00153 uplevel 1 [extract $text $terminals -metaprefix #]
00154 } res]
00155 info script $oldscr
00156 if {$code == 1} then {
00157 error $res $::errorInfo $::errorCode
00158 } else {
00159 return $res
00160 }
00161 }
00162
00163
00164