diff options
Diffstat (limited to 'tcllib/modules/docstrip/docstrip_util.tcl')
-rw-r--r-- | tcllib/modules/docstrip/docstrip_util.tcl | 649 |
1 files changed, 649 insertions, 0 deletions
diff --git a/tcllib/modules/docstrip/docstrip_util.tcl b/tcllib/modules/docstrip/docstrip_util.tcl new file mode 100644 index 0000000..b3a0009 --- /dev/null +++ b/tcllib/modules/docstrip/docstrip_util.tcl @@ -0,0 +1,649 @@ +## +## This is the file `docstrip_util.tcl', +## generated with the SAK utility +## (sak docstrip/regen). +## +## The original source files were: +## +## tcldocstrip.dtx (with options: `utilpkg') +## +## In other words: +## ************************************** +## * This Source is not the True Source * +## ************************************** +## the true source is the file from which this one was generated. +## +package require Tcl 8.4 +package require docstrip 1.2 +package provide docstrip::util 1.3.1 +namespace eval docstrip::util { + namespace export ddt2man guard patch thefile\ + packages_provided index_from_catalogue modules_from_catalogue\ + classical_preamble classical_postamble +} +namespace eval docstrip::util { + namespace import [namespace parent]::extract +} +proc docstrip::util::fileoptions {args} { + variable filename + variable thefile [eval [list thefile $filename] $args] + variable fileoptions $args +} +proc docstrip::util::Report {item} { + variable Report_store + if {$Report_store} then { + variable Report + lappend Report $item + } + variable Report_cmd + eval [linsert $Report_cmd end $item] +} +proc docstrip::util::index_from_catalogue {dir pattern args} { + array set O { + -options "" + -sourceconf "" + -report 0 + -reportcmd {puts stdout} + -RecursionDepth 0 + } + array set O $args + if {$O(-RecursionDepth)==0} then { + variable Report {} Report_store $O(-report) \ + Report_cmd $O(-reportcmd) + } + set targetFn [file join $dir pkgIndex.tcl] + Report "Entries will go to: $targetFn" + if {![file exists $targetFn]} then { + Report "Generating empty index file." + set F [open $targetFn w] + puts $F {# Tcl package index file, version 1.1} + puts $F {# This file is generated by the "pkg_mkIndex" command} + puts $F {# and sourced either when an application starts up or} + puts $F {# by a "package unknown" script. It invokes the} + puts $F {# "package ifneeded" command to set up package-related} + puts $F {# information so that packages will be loaded automatically} + puts $F {# in response to "package require" commands. When this} + puts $F {# script is sourced, the variable $dir must contain the} + puts $F {# full path name of this file's directory.} + close $F + } + set c [interp create -safe] + $c eval { + proc unknown args {} + } + $c alias pkgProvide [namespace which PkgProvide] + $c alias pkgIndex [namespace which PkgIndex] + $c alias fileoptions [namespace which fileoptions] + variable PkgIndex "" + foreach fn [glob -nocomplain -directory $dir -tails $pattern] { + Report "Processing file: $fn" + variable filename [file join $dir $fn] + variable fileoptions $O(-sourceconf) + variable thefile [eval [list thefile $filename] $fileoptions] + set catalogue [extract $thefile\ + [linsert $O(-options) 0 docstrip.tcl::catalogue]\ + -metaprefix {#} -onerror puts] + $c eval $catalogue + } + interp delete $c + if {$PkgIndex ne ""} then { + set F [open $targetFn {WRONLY APPEND}] + set cmd [list docstrip::util::index_from_catalogue $dir $pattern] + if {$O(-options) ne ""} then { + lappend cmd -options $O(-options) + } + if {$O(-sourceconf) ne ""} then { + lappend cmd -sourceconf $O(-sourceconf) + } + puts $F "\n## Appendix generated by:\n## $cmd$PkgIndex" + close $F + } + if {[info exists O(-recursein)]} then { + incr O(-RecursionDepth) + foreach fn [ + glob -nocomplain -tails -types d -directory $dir\ + $O(-recursein) + ] { + eval [list index_from_catalogue [file join $dir $fn] $pattern]\ + [array get O] + } + } + if {$O(-RecursionDepth)==0 && $O(-report)} then { + return [join $Report \n] + } +} +proc docstrip::util::PkgProvide {pkg ver terminals} { + if {[catch {package vcompare 0 $ver}]} then { + Report "Malformed version number $ver given for package $pkg." + return + } + variable PkgIndex + variable filename + variable fileoptions + append PkgIndex \n [list package ifneeded $pkg $ver] { "} + append PkgIndex [string map {\\ {\\} \$ {\$} \[ {\[} \" {\"}}\ + [list package provide $pkg $ver]] {; } + append PkgIndex {package require docstrip} {; } + append PkgIndex {[list docstrip::sourcefrom }\ + {[file join $dir } [list [file tail $filename]] {] }\ + [linsert $fileoptions 0 $terminals] {]"} +} +proc docstrip::util::PkgIndex {args} { + variable thefile + if {[catch { + packages_provided [extract $thefile $args -metaprefix {#}] + } res]} then { + if {[lindex $::errorCode 0] eq "DOCSTRIP"} then { + Report "Stripping error \"$res\"\nwhile indexing module\ + <[join $args ,]>." + } else { + Report "Code evaluation error:\n $res\nwhile indexing\ + module <[join $args ,]>." + } + } else { + variable filename + variable PkgIndex + variable fileoptions + foreach {pkg ver} $res { + append PkgIndex \n [list package ifneeded $pkg $ver] { "} + append PkgIndex {package require docstrip} {; } + append PkgIndex {[list docstrip::sourcefrom }\ + {[file join $dir } [list [file tail $filename]] {] }\ + [linsert $fileoptions 0 $args] {]"} + } + } +} +proc docstrip::util::modules_from_catalogue {target source args} { + array set Opt { + -formatpostamble {classical_postamble {##}} + -formatpreamble {classical_preamble {##}} + -options {} + -postamble {} + -preamble { } + -sourceconf {} + -report 1 + -reportcmd list + } + array set Opt $args + variable filename $source + variable fileoptions $Opt(-sourceconf) + variable thefile [eval [list thefile $source] $fileoptions] + variable Report {} Report_store $Opt(-report) \ + Report_cmd $Opt(-reportcmd) + set catalogue [extract $thefile\ + [linsert $Opt(-options) 0 docstrip.tcl::catalogue]\ + -metaprefix {#} -onerror puts] + set c [interp create -safe] + $c eval { + proc unknown args {} + } + $c alias pkgProvide\ + [namespace which GenerateNamedPkg] $target\ + [linsert $Opt(-formatpreamble) end $Opt(-preamble)]\ + [linsert $Opt(-formatpostamble) end $Opt(-postamble)] + $c alias pkgIndex\ + [namespace which GeneratePkg] $target\ + [linsert $Opt(-formatpreamble) end $Opt(-preamble)]\ + [linsert $Opt(-formatpostamble) end $Opt(-postamble)] + $c alias fileoptions [namespace which fileoptions] + $c eval $catalogue + interp delete $c + if {$Opt(-report)} then {return [join $Report \n]} +} +proc docstrip::util::GenerateNamedPkg\ + {target preamblecmd postamblecmd name version terminals} { + variable thefile + if {[catch { + extract $thefile $terminals -metaprefix {#} + } text]} then { + Report "Stripping error \"$text\"\nwhile indexing module\ + <[join $terminals ,]>." + } else { + variable filename + set module [format {%s-%s.tm}\ + [string trim [string map {:: /} $name] /] $version] + set modL [file split $module] + file mkdir [file join $target [file dirname $module]] + set F [open [file join $target $module] w] + fconfigure $F -encoding utf-8 + puts $F [eval $preamblecmd [list $module $filename $terminals]] + puts -nonewline $F $text + puts $F [eval $postamblecmd [list $module $filename $terminals]] + close $F + Report "Wrote $module" + } +} +proc docstrip::util::GeneratePkg {target preamblecmd postamblecmd args} { + variable thefile + if {[catch { + set text [extract $thefile $args -metaprefix {#}] + packages_provided $text + } res]} then { + if {[lindex $::errorCode 0] eq "DOCSTRIP"} then { + Report "Stripping error \"$res\"\nwhile indexing module\ + <[join $args ,]>." + } else { + Report "Code evaluation error:\n $res\nwhile indexing\ + module <[join $args ,]>." + } + } elseif {![llength $res]} then { + Report "Found no package in module <[join $args ,]>." + } else { + variable filename + set module [format {%s-%s.tm}\ + [string trim [string map {:: /} [lindex $res 0]] /]\ + [lindex $res 1]] + set modL [file split $module] + file mkdir [file join $target [file dirname $module]] + set F [open [file join $target $module] w] + fconfigure $F -encoding utf-8 + puts $F [eval $preamblecmd [list $module $filename $args]] + puts -nonewline $F $text + puts $F [eval $postamblecmd [list $module $filename $args]] + close $F + Report "Wrote $module" + foreach {pkg ver} [lreplace $res 0 1] { + set mod2 [format {%s-%s.tm}\ + [string trim [string map {:: /} $pkg] /] $ver] + set mod2L [file split $mod2] + file mkdir [file join $target [file dirname $mod2]] + set common 0 + foreach d1 $modL d2 $mod2L { + if {$d1 eq $d2} then {incr common} else {break} + } + set tail [lrange $modL $common end] + set script {[::info script]} + foreach d2 $mod2L { + if {[incr common -1] < 0} then { + set script "\[::file dirname $script\]" + } + } + set F [open [file join $target $mod2] w] + fconfigure $F -encoding utf-8 + puts $F "::source -encoding utf-8 \[::file join $script $tail\]" + close $F + Report "Wrote redirect $mod2" + } + } +} +proc docstrip::util::classical_preamble {metaprefix message target args} { + set res {""} + lappend res " This is `$target'," + lappend res { generated by the docstrip::util package.} + lappend res {} { The original source files were:} {} + foreach {source terminals} $args { + set line " [file tail $source]" + if {[llength $terminals]} then { + append line { (with options: `} [join $terminals ,] {')} + } + lappend res $line + } + foreach line [split $message \n] {lappend res " $line"} + return $metaprefix[join $res "\n$metaprefix"] +} +proc docstrip::util::classical_postamble {metaprefix message target args} { + set res {} + foreach line [split $message \n] {lappend res " $line"} + lappend res {} " End of file `$target'." + return $metaprefix[join $res "\n$metaprefix"] +} +proc docstrip::util::packages_provided {text {setup ""}} { + set c [interp create -safe] + $c eval { + proc tclPkgUnknown args {} + package unknown tclPkgUnknown + proc unknown {args} {} + proc auto_import {args} {} + } + $c hide package + $c alias package [namespace which packages_provided,package] $c + eval $setup + set package_list {} + catch {$c eval $text} + interp delete $c + return $package_list +} +proc docstrip::util::packages_provided,package {interp subcmd args} { + switch -- $subcmd { + r - re - req - requ - requi - requir - require { + return + } + pro - prov - provi - provid - provide { + if {[llength $args] == 2} then { + uplevel 1 [list lappend package_list] $args + } + } + } + eval [list $interp invokehidden package $subcmd] $args +} +proc docstrip::util::ddt2man {text} { + set wascode 0 + set verbatim 0 + set res "" + foreach line [split $text \n] { + if {$verbatim} then { + if {$line eq $endverbline} then { + set verbatim 0 + } else { + append res [string map {[ [lb] ] [rb]} $line] \n + } + } else { + switch -glob -- $line %%* { + if {$wacode} then { + append res {[example_end]} \n + set wascode 0 + } + append res [string range $line 2 end] \n + } %<<* { + if {!$wascode} then { + append res {[example_begin]} \n + set wascode 1 + } + set endverbline "%[string range $line 3 end]" + set verbatim 1 + } %<* { + if {!$wascode} then { + append res {[example_begin]} \n + set wascode 1 + } + set guard "" + regexp -- {(^%<[^>]*>)(.*)$} $line "" guard line + append res \[ [list emph $guard] \]\ + [string map {[ [lb] ] [rb]} $line] \n + } %* { + if {$wascode} then { + append res {[example_end]} \n + set wascode 0 + } + append res [string range $line 1 end] \n + } {\\endinput} { + break + } "" { + append res \n + } default { + if {!$wascode} then { + append res {[example_begin]} \n + set wascode 1 + } + append res [string map {[ [lb] ] [rb]} $line] \n + } + } + } + if {$wascode} then {append res {[example_end]} \n} + return $res +} +proc docstrip::util::guards {subcmd text} { + set verbatim 0 + set lineno 1 + set badL {} + foreach line [split $text \n] { + if {$verbatim} then { + if {$line eq $endverbline} then {set verbatim 0} + } else { + switch -glob -- $line %<<* { + set endverbline "%[string range $line 3 end]" + set verbatim 1 + } %<* { + if {![ + regexp -- {^%<([*/+-]?)([^>]*)>(.*)$} $line ""\ + modifier expression line + ]} then { + lappend badL $lineno $line + } else { + if {$modifier eq ""} then {set modifier " "} + append E($expression) $modifier + } + } + } + incr lineno + } + if {$subcmd eq "rotten"} then {return $badL} + switch -- $subcmd "exprmods" { + return [array get E] + } "expressions" { + return [array names E] + } "exprerr" { + set res {} + foreach expr [array names E] { + regsub -all {[^()!,|&]+} $expr 0 e + regsub -all {,} $e {|} e + if {[catch {expr $e}]} then {lappend res $expr} + } + return $res + } + foreach name [array names E] { + set E($name) [string length $E($name)] + } + if {$subcmd eq "exprcounts"} then {return [array get E]} + foreach expr [array names E] { + foreach term [split $expr "()!,|&"] { + if {$term eq ""} then {continue} + if {![info exists T($term)]} then {set T($term) 0} + incr T($term) $E($expr) + } + } + switch -- $subcmd "counts" { + return [array get T] + } "names" { + return [array names T] + } default { + error "Unknown subcommand '$subcmd', must be one of:\ + counts, exprcounts, expressions, exprmods, names, rotten" + } +} +proc docstrip::util::patch {sourcevar termL fromtext diff args} { + upvar 1 $sourcevar SL + array set O {-trimlines 1 -matching exact} + array set O $args + set cmd [list extract [join $SL \n] $termL -annotate 2] + foreach opt {-metaprefix -trimlines} { + if {[info exists O($opt)]} then {lappend cmd $opt $O($opt)} + } + set EL [split [eval $cmd] \n] + lset EL end \n + set ptr 0 + set lineno 1 + set FL [list {}] + foreach line [split $fromtext \n] { + lappend FL $line + if {$O(-trimlines)} then {set line [string trimright $line " "]} + if {$line eq [lindex $EL $ptr]} then { + set lift($lineno) [lindex $EL [incr ptr]] + lset lift($lineno) 0 [expr { [lindex $EL [incr ptr]] - 1 }] + incr ptr + } + incr lineno + } + if {![array size lift]} then { + return -code error "The extract did not match any part of the\ + fromtext. Check the list of terminals and the options" + } + set RL [list] + set log [list] + foreach hunk [lsort -decreasing -integer -index 0 $diff] { + set replL [list] + set l1 [lindex $hunk 0] + set repl {0 -1} + set matches 1 + foreach {type line} [lindex $hunk 4] { + switch -glob -- $type {[0-]} { + switch -- $O(-matching) "exact" { + if {[lindex $FL $l1] ne $line} then {set matches 0} + } "nonspace" { + if {[regsub -all -- {\s} $line {}] ne\ + [regsub -all -- {\s} [lindex $FL $l1] {}]} then { + set matches 0 + } + } "anyspace" { + if {[regsub -all -- {\s+} $line { }] ne\ + [regsub -all -- {\s+} [lindex $FL $l1] { }]} then { + set matches 0 + } + } + } + switch -- $type synch { + if {[llength $repl]>2 ||\ + [lindex $repl 1]-[lindex $repl 0]>=0} then { + lappend replL $repl + } + set repl [list $l1 [expr {$l1-1}]] + } + { + lappend repl $line + } - { + lset repl 1 $l1 + incr l1 + } 0 { + if {[llength $repl]>2 ||\ + [lindex $repl 1]-[lindex $repl 0]>=0} then { + lappend replL $repl + set repl {0 -1} + } + lset repl 1 $l1 + incr l1 + lset repl 0 $l1 + } + } + if {[llength $repl]>2 || [lindex $repl 1]-[lindex $repl 0]>=0}\ + then {lappend replL $repl} + if {$matches} then { + lappend hunk [lsort -decreasing -integer -index 0 $replL] + lappend RL $hunk + } else { + lappend hunk "(-- did not match fromtext --)" + lappend log $hunk + } + } + foreach hunk $RL { + set applied 0 + set misapplied 0 + foreach repl [lindex $hunk 5] { + unset -nocomplain from to + for {set n [lindex $repl 1]} {$n>=[lindex $repl 0]}\ + {incr n -1} { + if {![info exists lift($n)]} then { + incr misapplied + continue + } elseif {![info exists from]} then { + set to [lindex $lift($n) 0] + set from $to + } elseif {[lindex $lift($n) 0] == $from-1} then { + set from [lindex $lift($n) 0] + } else { + set SL [lreplace $SL $from $to] + set to [lindex $lift($n) 0] + set from $to + } + incr applied + set n0 $n + } + if {[info exists from]} then { + set sprefix [lindex $lift($n0) 1] + set eprefix [lindex $lift($n0) 2] + } elseif {[info exists lift([lindex $repl 0])]} then { + foreach {from sprefix eprefix} $lift([lindex $repl 0])\ + break + set to [expr {$from-1}] + } else { + incr misapplied [llength [lrange $repl 2 end]] + continue + } + set eplen [string length $eprefix] + set epend [expr {$eplen-1}] + set cmd [list lreplace $SL $from $to] + foreach line [lrange $repl 2 end] { + if {$eprefix eq [string range $line 0 $epend]} then { + lappend cmd "$sprefix[string range $line $eplen end]" + } else { + lappend cmd $line + } + incr applied + } + set SL [eval $cmd] + } + if {$misapplied>0} then { + if {$applied>0} then { + lset hunk 5 "(-- was partially applied --)" + } else { + lset hunk 5 "(not applied)" + } + lappend log $hunk + } + } + set res "" + foreach hunk [lsort -index 0 -integer $log] { + foreach {start1 end1 start2 end2 lines msg} $hunk break + append res [format "@@ -%d,%d +%d,%d @@ %s\n"\ + $start1 [expr {$end1-$start1+1}]\ + $start2 [expr {$end2-$start2+1}] $msg] + foreach {type line} $lines { + switch -- $type 0 { + append res " " $line \n + } - - + { + append res $type $line \n + } + } + } + return $res +} +proc docstrip::util::thefile {fname args} { + set F [open $fname r] + if {[llength $args]} then { + if {[set code [ + catch {eval [linsert $args 0 fconfigure $F]} res + ]]} then { + close $F + return -code $code -errorinfo $::errorInfo -errorcode\ + $::errorCode + } + } + catch {read -nonewline $F} res + close $F + return $res +} +proc docstrip::util::import_unidiff {text {warnvar ""}} { + if {$warnvar ne ""} then {upvar 1 $warnvar warning} + set inheader 1 + set res [list] + set lines [list] + set end2 "not an integer" + foreach line [split $text \n] { + if {$inheader && [regexp {^(---|\+\+\+)} $line]}\ + then {continue} + switch -glob -- $line { *} { + lappend lines 0 [string range $line 1 end] + } {+*} { + lappend lines + [string range $line 1 end] + } {-*} { + lappend lines - [string range $line 1 end] + } @@* { + if {[string is integer $end2]} then { + lappend res [list $start1 $end1 $start2 $end2 $lines] + } + set len2 [set len1 ,1] + if {[ + regexp {^@@ -([0-9]+)(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@}\ + $line -> start1 len1 start2 len2 + ] && [scan "$start1 $len1,1" {%d ,%d} start1 len1]==2 &&\ + [scan "$start2 $len2,1" {%d ,%d} start2 len2]==2 + } then { + set end1 [expr {$start1+$len1-1}] + set end2 [expr {$start2+$len2-1}] + set inheader 0 + } else { + set end2 "not an integer" + append warning "Could not parse hunk header: " $line \n + } + set lines [list] + } "" { + } default { + append warning "Could not parse line: " $line \n + } + } + if {[string is integer $end2]} then { + lappend res [list $start1 $end1 $start2 $end2 $lines] + } + return $res +} +## +## +## End of file `docstrip_util.tcl'.
\ No newline at end of file |