## 
## 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
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 $O(-report) \
     Report_cmd $O(-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 {$O(-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'.