Tcl Library Source Code

Check-in [e6100e18d0]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added an auto-documenter to the doctools module for use in module that build amalgamations in the same style a practcl, clay, and httpd. Practcl and Httpd now generate their manual page in this new manner. The positive is that every proc, class, and method are now auto-documented with arguments, even if we don't have comments for them yet.
Timelines: family | ancestors | descendants | both | hypnotoad
Files: files | file ages | folders
SHA3-256:e6100e18d0dd9ca1755ce531f2e9feacc47fe269b755bc602819cfb09dc63be0
User & Date: hypnotoad 2018-09-15 23:15:14
Context
2018-09-16
09:22
More refinements to the docbuild tool. Updated documentation for httpd and practcl check-in: 1fd28c318f user: hypnotoad tags: hypnotoad
2018-09-15
23:15
Added an auto-documenter to the doctools module for use in module that build amalgamations in the same style a practcl, clay, and httpd. Practcl and Httpd now generate their manual page in this new manner. The positive is that every proc, class, and method are now auto-documented with arguments, even if we don't have comments for them yet. check-in: e6100e18d0 user: hypnotoad tags: hypnotoad
14:04
httpd modifications: The manual file for httpd is now generated dynamically during the call to build/build.tcl and is developed by scanning the source files and scraping comments. The test.tcl file generated during httpd.test is now deleted prior to ending the test. Redistributed the hard coded documentation files as comments in front of the methods they describe to be assembled by the manual file generator. check-in: ac0f7f67c2 user: hypnotoad tags: hypnotoad
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added modules/doctools/docbuild.tcl.































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
###
# Tool for build scripts to dynamically generate manual files from comments
# in source code files
###
package provide doctools::build 0.1

namespace eval ::docbuild {}


oo::class create ::docbuild::object {
  constructor {} {
    my variable coro
    set coro [info object namespace [self]]::coro
    oo::objdefine [self] forward coro $coro
    coroutine $coro {*}[namespace code {my reset}]
  }

  method arglist {arglist} {
    set result [dict create]
    foreach arg $arglist {
      set name [lindex $arg 0]
      dict set result $name positional 1
      dict set result $name mandatory  1
      if {$name in {args dictargs}} {
        switch [llength $arg] {
          1 {
            dict set result $name mandatory 0
          }
          2 {
            dict for {optname optinfo} [lindex $arg 1] {
              set optname [string trim $optname -:]
              dict set result $optname {positional 1 mandatory 0}
              dict for {f v} $optinfo {
                dict set result $optname [string trim $f -:] $v
              }
            }
          }
          default {
            error "Bad argument"
          }
        }
      } else {
        switch [llength $arg] {
          1 {
            dict set result $name mandatory 1
          }
          2 {
            dict set result $name mandatory 0
            dict set result $name default   [lindex $arg 1]
          }
          default {
            error "Bad argument"
          }
        }
      }
    }
    return $result
  }

  method comment block {
    return [dict create comment $block]
  }

  method keyword.class {resultvar commentblock name body} {
    upvar 1 $resultvar result
    set info [my comment $commentblock]
    set commentblock {}
    foreach line [split $body \n] {
      append thisline $line \n
      if {![info complete $thisline]} continue
      set thisline [string trim $thisline]
      if {[string index $thisline 0] eq "#"} {
        append commentblock [string trimleft $thisline #] \n
        set thisline {}
        continue
      }
      set cmd [string trim [lindex $thisline 0] ":"]
      switch $cmd {
        superclass {
          dict set info ancestors [lrange $thisline 1 end]
          set commentblock {}
        }
        destructor -
        constructor {
          my keyword.method info $commentblock {*}[lrange $thisline 0 end-1]
          set commentblock {}
        }
        method -
        Ensemble {
          my keyword.method info $commentblock  {*}[lrange $thisline 1 end-1]
          set commentblock {}
        }
      }
      set thisline {}
    }
    dict set result class $name $info
  }

  method keyword.method {resultvar commentblock name args} {
    upvar 1 $resultvar result
    set info [my comment $commentblock]
    switch [llength $args] {
      1 {
        set arglist [lindex $args 0]
      }
      0 {
        set arglist dictargs
        #set body [lindex $args 0]
      }
      default {error "could not interpret method $name {*}$args"}
    }
    if {![dict exists $info arglist]} {
      dict set info arglist [my arglist $arglist]
    }
    dict set result method [string trim $name :] $info
  }

  method keyword.proc {commentblock name arglist body} {
    set info [my comment $commentblock]
    if {![dict exists $info arglist]} {
      dict set info arglist [my arglist $arglist]
    }
    return $info
  }

  method reset {} {
    my variable info
    set info [dict create]
    yield [info coroutine]
    set thisline {}
    set commentblock {}
    set linec 0
    while 1 {
      set line [yield]
      append thisline $line \n
      if {![info complete $thisline]} continue
      set thisline [string trim $thisline]
      if {[string index $thisline 0] eq "#"} {
        append commentblock [string trimleft $thisline #] \n
        set thisline {}
        continue
      }
      set cmd [string trim [lindex $thisline 0] ":"]
      switch $cmd {
        if {
          # Handle an if statement
          foreach {expr body} [lrange $thisline 1 end] {


          }
        }
        proc {
          set procinfo [my keyword.proc $commentblock {*}[lrange $thisline 1 end]]
          dict set info proc [string trim [lindex $thisline 1] :] $procinfo
          set commentblock {}
        }
        oo::define {
          if {[llength $thisline]==3} {
            lassign $thisline tcmd name body
            my keyword.class info $commentblock $name $body
          } else {
            puts "Warning: bare oo::define in library"
          }
        }
        tao::define -
        clay::define -
        tool::define {
          lassign $thisline tcmd name body
          my keyword.class info $commentblock $name $body
          set commentblock {}
        }
        oo::class {
          lassign $thisline tcmd mthd name body
          my keyword.class info $commentblock $name $body
          set commentblock {}
        }
      }
      set thisline {}
    }
  }

  method section.command {procinfo} {
    set result {}
    putb result "\[section \{Commands\}\]"
    putb result {[list_begin definitions]}
    dict for {method minfo} $procinfo {
      putb result {}
      set line "\[call proc \[cmd $method\]"
      if {[dict exists $minfo arglist]} {
        dict for {argname arginfo} [dict get $minfo arglist] {
          set positional 1
          set mandatory  1
          dict with arginfo {}
          if {$mandatory==0} {
            append line " ?"
          } else {
            append line " "
          }
          if {$positional} {
            append line "\[arg $argname"
          } else {
            append line "\[opt $argname"
            if {[dict exists $arginfo type]} {
              append line " \[cmd [dict get $arginfo type]\]"
            } else {
              append line " \[cmd $argname\]"
            }
          }
          append line "\]"
          if {$mandatory==0} {
            if {[dict exists $arginfo default]} {
              append line " \[emph \"[dict get $arginfo default]\"\]"
            }
            append line "?"
          }
        }
      }
      append line \]
      putb result $line
      if {[dict exists $minfo comment]} {
        putb result [dict get $minfo comment]
      }
    }
    putb result {[list_end]}
    return $result
  }

  method section.class {class_name class_info} {
    set result {}
    putb result "\[section \{Class  $class_name\}\]"
    if {[dict exists $class_info method]} {
      putb result {[list_begin definitions]}
      dict for {method minfo} [dict get $class_info method] {
        putb result {}
        set line "\[call method \[cmd $method\]"
        if {[dict exists $minfo arglist]} {
          dict for {argname arginfo} [dict get $minfo arglist] {
            set positional 1
            set mandatory  1
            dict with arginfo {}
            if {$mandatory==0} {
              append line " ?"
            } else {
              append line " "
            }
            if {$positional} {
              append line "\[arg $argname"
            } else {
              append line "\[opt $argname"
              if {[dict exists $arginfo type]} {
                append line " \[cmd [dict get $arginfo type]\]"
              } else {
                append line " \[cmd $argname\]"
              }
            }
            append line "\]"
            if {$mandatory==0} {
              if {[dict exists $arginfo default]} {
                append line " \[emph \"[dict get $arginfo default]\"\]"
              }
              append line "?"
            }
          }
        }
        append line \]
        putb result $line
        if {[dict exists $minfo comment]} {
          putb result [dict get $minfo comment]
        }
      }
      putb result {[list_end]}
    }
    if {[dict exists $class_info comment]} {
      putb result [dict get $class_info comment]
    }
    return $result
  }

  method manpage args {
    my variable info map
    set result {}
    set header {}
    set footer {}
    dict with args {}
    putb result $header
    dict for {sec_type sec_info} $info {
      switch $sec_type {
        proc {
          putb result [my section.command $sec_info]
        }
        class {
          dict for {class_name class_info} $sec_info {
            putb result [my section.class $class_name $class_info]
          }
        }
        default {
          putb result "\[section [list $sec_type $sec_name]\]"
          if {[dict exists $sec_info comment]} {
            putb result [dict get $sec_info comment]
          }
        }
      }
    }
    putb result $footer
    putb result {[manpage_end]}
    return $result
  }

  method scan_text {text} {
    my variable linecount coro
    set linecount 0
    foreach line [split $text \n] {
      incr linecount
      $coro $line
    }
  }

  method scan_file {filename} {
    my variable linecount coro
    set fin [open $filename r]
    set linecount 0
    while {[gets $fin line]>=0} {
      incr linecount
      $coro $line
    }
    close $fin
  }
}

proc ::docbuild::cat filename {
  set fin [open $filename r]
  set data [read $fin]
  close $fin
  return $data
}


proc ::putb {buffername args} {
  upvar 1 $buffername buffer
  switch [llength $args] {
    1 {
      append buffer [lindex $args 0] \n
    }
    2 {
      append buffer [string map {*}$args] \n
    }
    default {
      error "usage: putb buffername ?map? string"
    }
  }
}

Changes to modules/doctools/pkgIndex.tcl.

1
2
3
4
5
6


if {![package vsatisfies [package provide Tcl] 8.2]} {return}
package ifneeded doctools            1.4.21 [list source [file join $dir doctools.tcl]]
package ifneeded doctools::toc       1.1.7  [list source [file join $dir doctoc.tcl]]
package ifneeded doctools::idx       1.0.8  [list source [file join $dir docidx.tcl]]
package ifneeded doctools::cvs       1      [list source [file join $dir cvs.tcl]]
package ifneeded doctools::changelog 1.1    [list source [file join $dir changelog.tcl]]








>
>
1
2
3
4
5
6
7
8
if {![package vsatisfies [package provide Tcl] 8.2]} {return}
package ifneeded doctools            1.4.21 [list source [file join $dir doctools.tcl]]
package ifneeded doctools::toc       1.1.7  [list source [file join $dir doctoc.tcl]]
package ifneeded doctools::idx       1.0.8  [list source [file join $dir docidx.tcl]]
package ifneeded doctools::cvs       1      [list source [file join $dir cvs.tcl]]
package ifneeded doctools::changelog 1.1    [list source [file join $dir changelog.tcl]]
if {![package vsatisfies [package provide Tcl] 8.6]} {return}
package ifneeded doctools::build 0.1    [list source [file join $dir docbuild.tcl]]

Changes to modules/httpd/build/build.tcl.

1
2
3


4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
...
197
198
199
200
201
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309

310
311
312

313
set srcdir [file dirname [file normalize [file join [pwd] [info script]]]]
set moddir [file dirname $srcdir]



set version 4.3
set tclversion 8.6
set module [file tail $moddir]
set filename $module

proc autodoc.arglist {arglist} {
  set result [dict create]
  foreach arg $arglist {
    set name [lindex $arg 0]
    dict set result $name positional 1
    dict set result $name mandatory  1
    if {$name in {args dictargs}} {
      switch [llength $arg] {
        1 {
          dict set result $name mandatory 0
        }
        2 {
          dict for {optname optinfo} [lindex $arg 1] {
            set optname [string trim $optname -:]
            dict set result $optname {positional 1 mandatory 0}
            dict for {f v} $optinfo {
              dict set result $optname [string trim $f -:] $v
            }
          }
        }
        default {
          error "Bad argument"
        }
      }
    } else {
      switch [llength $arg] {
        1 {
          dict set result $name mandatory 1
        }
        2 {
          dict set result $name mandatory 0
          dict set result $name default   [lindex $arg 1]
        }
        default {
          error "Bad argument"
        }
      }
    }
  }
  return $result
}

proc autodoc.proc {resultvar commentblock name arglist body} {
  upvar 1 $resultvar result
  set info [autodoc.comment $commentblock]
  if {![dict exists $info arglist]} {
    dict set info arglist [autodoc.arglist $arglist]
  }
  dict set result proc [string trim $name :] $info
}

proc autodoc.method {resultvar commentblock name args} {
  upvar 1 $resultvar result
  set info [autodoc.comment $commentblock]
  switch [llength $args] {
    1 {
      set arglist [lindex $args 0]
    }
    0 {
      set arglist dictargs
      #set body [lindex $args 0]
    }
    default {error "could not interpret method $name {*}$args"}
  }
  if {![dict exists $info arglist]} {
    dict set info arglist [autodoc.arglist $arglist]
  }
  dict set result method [string trim $name :] $info
}

proc autodoc.class {resultvar commentblock name body} {
  upvar 1 $resultvar result
  set info [autodoc.comment $commentblock]
  set commentblock {}
  foreach line [split $body \n] {
    append thisline $line \n
    if {![info complete $thisline]} continue
    set thisline [string trim $thisline]
    if {[string index $thisline 0] eq "#"} {
      append commentblock [string trimleft $thisline #] \n
      set thisline {}
      continue
    }
    set cmd [string trim [lindex $thisline 0] ":"]
    switch $cmd {
      superclass {
        dict set info ancestors [lrange $thisline 1 end]
        set commentblock {}
      }
      destructor -
      constructor {
        autodoc.method info $commentblock {*}[lrange $thisline 0 end-1]
        set commentblock {}
      }
      method -
      Ensemble {
        autodoc.method info $commentblock  {*}[lrange $thisline 1 end-1]
        set commentblock {}
      }
    }
    set thisline {}
  }
  dict set result class $name $info
}


proc autodoc.comment block {
  return [dict create comment $block]
}

proc autodoc.root {resultvar} {
  upvar 1 $resultvar result
  yield [info coroutine]
  set thisline {}
  set commentblock {}
  set linec 0
  while 1 {
    set line [yield]
    append thisline $line \n
    if {![info complete $thisline]} continue
    set thisline [string trim $thisline]
    if {[string index $thisline 0] eq "#"} {
      append commentblock [string trimleft $thisline #] \n
      set thisline {}
      continue
    }
    set cmd [string trim [lindex $thisline 0] ":"]
    switch $cmd {
      proc {
        autodoc.proc result $commentblock {*}[lrange $thisline 1 end]
        set commentblock {}
      }
      oo::define {
        if {[llength $thisline]==3} {
          lassign $thisline tcmd name body
          autodoc.class $commentblock $name $body
        } else {
          puts "Warning: bare oo::define in library"
        }
      }
      clay::define -
      tool::define {
        lassign $thisline tcmd name body
        autodoc.class result $commentblock $name $body
        set commentblock {}
      }
      oo::class {
        lassign $thisline tcmd mthd name body
        autodoc.class result $commentblock $name $body
        set commentblock {}
      }
    }
    set thisline {}
  }
}

set AutoDocInfo [dict create]
coroutine AutoDoc autodoc.root AutoDocInfo


set fout [open [file join $moddir ${filename}.tcl] w]
dict set map %module% $module
dict set map %version% $version
dict set map %tclversion% $tclversion
dict set map %filename% $filename
dict set map {    } {} ;# strip indentation
................................................................................
  file.tcl
  proxy.tcl
  cgi.tcl
  scgi.tcl
  websocket.tcl
} {
  lappend loaded $file
  set fin [open [file join $srcdir $file] r]
  puts $fout "###\n# START: [file tail $file]\n###"
  set content [read $fin]
  close $fin
  puts $file
  foreach line [split $content \n] {

    AutoDoc $line
  }
  puts $fout $content
  puts $fout "###\n# END: [file tail $file]\n###"
}
# These files can be loaded in any order
foreach file [glob [file join $srcdir *.tcl]] {
  if {[file tail $file] in $loaded} continue
  lappend loaded $file
  set fin [open [file join $srcdir $file] r]
  puts $fout "###\n# START: [file tail $file]\n###"
  set content [read $fin]
  close $fin
  puts $file
  foreach line [split $content \n] {
    AutoDoc $line
  }
  puts $fout $content
  puts $fout "###\n# END: [file tail $file]\n###"
}

# Provide some cleanup and our final package provide
puts $fout [string map $map {
    namespace eval ::%module% {
................................................................................
set fout [open [file join $moddir pkgIndex.tcl] w]
puts $fout [string map $map {
    if {![package vsatisfies [package provide Tcl] %tclversion%]} {return}
    package ifneeded %module% %version% [list source [file join $dir %module%.tcl]]
}]
close $fout

###
# Build the help file
###
set manout [open [file join $moddir $filename.man] w]
set fin    [open [file join $srcdir manual.txt] r]
puts $manout [string map $map [read $fin]]
close $fin
foreach type [dict keys $AutoDocInfo] {
  dict for {name info} [dict get $AutoDocInfo $type] {
    if {$type eq "class"} {
      puts $manout "\[section \{Class  $name\}\]"
      if {[dict exists $info method]} {
        puts $manout {[list_begin definitions]}
        dict for {method minfo} [dict get $info method] {
          puts $manout {}
          set line "\[call method \[cmd $method\]"
          if {[dict exists $minfo arglist]} {
            dict for {argname arginfo} [dict get $minfo arglist] {
              set positional 1
              set mandatory  1
              dict with arginfo {}
              if {$mandatory==0} {
                append line " ?"
              } else {
                append line " "
              }
              if {$positional} {
                append line "\[arg $argname"
              } else {
                append line "\[opt $argname"
                if {[dict exists $arginfo type]} {
                  append line " \[cmd [dict get $arginfo type]\]"
                } else {
                  append line " \[cmd $argname\]"
                }
              }
              append line "\]"
              if {$mandatory==0} {
                if {[dict exists $arginfo default]} {
                  append line " \[emph \"[dict get $arginfo default]\"\]"
                }
                append line "?"
              }
            }
          }
          append line \]
          puts $manout $line
          if {[dict exists $minfo comment]} {
            puts $manout [dict get $minfo comment]
          }
        }
        puts $manout {[list_end]}
      }
    } else {
      puts $manout "\[section [list $type $name]\]"
    }
    if {[dict exists $info comment]} {
      puts $manout [dict get $info comment]
    }
  }
}

set fin    [open [file join $srcdir footer.txt] r]
puts $manout [string map $map [read $fin]]
close $fin

close $manout



>
>




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<

<
<
<
<
>
|
<









|
<
<
<
|
<







 







<
<
<

<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
|
<
<
>

1
2
3
4
5
6
7
8
9
































































































































































10
11
12
13
14
15
16
..
39
40
41
42
43
44
45

46




47
48

49
50
51
52
53
54
55
56
57
58



59

60
61
62
63
64
65
66
..
75
76
77
78
79
80
81



82










83














































84
85


86
87
set srcdir [file dirname [file normalize [file join [pwd] [info script]]]]
set moddir [file dirname $srcdir]

source [file join $moddir .. doctools docbuild.tcl]
::docbuild::object create AutoDoc
set version 4.3
set tclversion 8.6
set module [file tail $moddir]
set filename $module

































































































































































set fout [open [file join $moddir ${filename}.tcl] w]
dict set map %module% $module
dict set map %version% $version
dict set map %tclversion% $tclversion
dict set map %filename% $filename
dict set map {    } {} ;# strip indentation
................................................................................
  file.tcl
  proxy.tcl
  cgi.tcl
  scgi.tcl
  websocket.tcl
} {
  lappend loaded $file

  puts $fout "###\n# START: [file tail $file]\n###"




  set content [::docbuild::cat [file join $srcdir $file]]
  AutoDoc scan_text $content

  puts $fout $content
  puts $fout "###\n# END: [file tail $file]\n###"
}
# These files can be loaded in any order
foreach file [glob [file join $srcdir *.tcl]] {
  if {[file tail $file] in $loaded} continue
  lappend loaded $file
  set fin [open [file join $srcdir $file] r]
  puts $fout "###\n# START: [file tail $file]\n###"
  set content [::docbuild::cat [file join $srcdir $file]]



  AutoDoc scan_text $content

  puts $fout $content
  puts $fout "###\n# END: [file tail $file]\n###"
}

# Provide some cleanup and our final package provide
puts $fout [string map $map {
    namespace eval ::%module% {
................................................................................
set fout [open [file join $moddir pkgIndex.tcl] w]
puts $fout [string map $map {
    if {![package vsatisfies [package provide Tcl] %tclversion%]} {return}
    package ifneeded %module% %version% [list source [file join $dir %module%.tcl]]
}]
close $fout




set manout [open [file join $moddir $filename.man] w]










puts $manout [AutoDoc manpage \














































  header [string map $map [::docbuild::cat [file join $srcdir manual.txt]]] \
  footer [string map $map [::docbuild::cat [file join $srcdir footer.txt]]] \


]
close $manout

Changes to modules/httpd/build/footer.txt.

1
2
3
4
5
6
[section AUTHORS]
Sean Woods

[vset CATEGORY network]
[include ../doctools2base/include/feedback.inc]
[manpage_end]





<
1
2
3
4
5

[section AUTHORS]
Sean Woods

[vset CATEGORY network]
[include ../doctools2base/include/feedback.inc]

Changes to modules/httpd/httpd.man.

98
99
100
101
102
103
104

105
106
107
108
109
110
111
...
478
479
480
481
482
483
484

485
486
487
488
489
490
491
...
664
665
666
667
668
669
670

671
672
673
674

675
676
677
678
679
680
681
682
683
684
685

686
687
688
689
690
691
692

693
694
695
696
697
698
699

700
701
702
703
704
705
706
...
714
715
716
717
718
719
720

721
722
723
724
725
726
727
728
729
730

731
732
733
734
735
736
737
...
745
746
747
748
749
750
751

752
753
754
755
756
757
758
...
768
769
770
771
772
773
774

775
776
777
778
779
780
781
782
783

784
785
786
787
788
789
790
...
794
795
796
797
798
799
800

801
802
803
804
805
806
807
808
809
810
811
812
813

814
815
816
817
818

819
820
821
822

823
824
825
826
827
828
829
...
839
840
841
842
843
844
845

846
847
848
849
850
851
852
853
854
855
856
857
858

859
860
861
862
863
864
865
...
869
870
871
872
873
874
875

876
877
878
879
880
881

882
883

 The working elements have been updated to operate as a TclOO object
 running with Tcl 8.6+. Global variables and hard coded tables are
 now resident with the object, allowing this server to be more easily
 embedded another program, as well as be adapted and extended to
 support the SCGI module



[section {Class  ::httpd::reply}]
[list_begin definitions]

[call method [cmd constructor] [arg ServerObj] ?[arg args]?]


................................................................................
     my puts [my html footer]
 	}
 }

 }]
 [list_end]



[section {Class  ::httpd::server}]
[list_begin definitions]

[call method [cmd constructor] [arg args] ?[arg port] [emph "auto"]? ?[arg myaddr] [emph "127.0.0.1"]? ?[arg string] [emph "auto"]? ?[arg name] [emph "auto"]? ?[arg doc_root] [emph ""]? ?[arg reverse_dns] [emph "0"]? ?[arg configuration_file] [emph ""]? ?[arg protocol] [emph "HTTP/1.1"]?]


................................................................................
[list_end]

 An httpd server with a template engine and a shim to insert URL domains.

 This class is the root object of the webserver. It is responsible
 for opening the socket and providing the initial connection negotiation.



[section {Class  ::httpd::server::dispatch}]

 Provide a backward compadible alias



[section {Class  ::httpd::content.redirect}]
[list_begin definitions]

[call method [cmd reset]]


[call method [cmd content]]

[list_end]


[section {Class  ::httpd::content.cache}]
[list_begin definitions]

[call method [cmd Dispatch]]

[list_end]


[section {Class  ::httpd::content.template}]
[list_begin definitions]

[call method [cmd content]]

[list_end]


[section {Class  ::httpd::content.file}]
[list_begin definitions]

[call method [cmd FileName]]


................................................................................

[list_end]

 Class to deliver Static content
 When utilized, this class is fed a local filename
 by the dispatcher



[section {Class  ::httpd::content.exec}]
[list_begin definitions]

[call method [cmd CgiExec] [arg execname] [arg script] [arg arglist]]


[call method [cmd Cgi_Executable] [arg script]]

[list_end]


[section {Class  ::httpd::content.proxy}]
[list_begin definitions]

[call method [cmd proxy_channel]]


................................................................................


[call method [cmd Dispatch]]

[list_end]

 Return data from an proxy process



[section {Class  ::httpd::content.cgi}]
[list_begin definitions]

[call method [cmd FileName]]

................................................................................

[call method [cmd DirectoryListing] [arg local_file]]

 For most CGI applications a directory list is vorboten


[list_end]


[section {Class  ::httpd::protocol.scgi}]
[list_begin definitions]

[call method [cmd EncodeStatus] [arg status]]

[list_end]

 Return data from an SCGI process



[section {Class  ::httpd::content.scgi}]
[list_begin definitions]

[call method [cmd scgi_info]]

................................................................................

[call method [cmd ProxyRequest] [arg chana] [arg chanb]]


[call method [cmd ProxyReply] [arg chana] [arg chanb] ?[arg args]?]

[list_end]


[section {Class  ::httpd::server.scgi}]
[list_begin definitions]

[call method [cmd debug] ?[arg args]?]


[call method [cmd Connect] [arg uuid] [arg sock] [arg ip]]

[list_end]

 Act as an  SCGI Server



[section {Class  ::httpd::content.websocket}]

 Upgrade a connection to a websocket



[section {Class  ::httpd::plugin}]

 httpd plugin template



[section {Class  ::httpd::plugin.dict_dispatch}]
[list_begin definitions]

[call method [cmd Dispatch_Dict] [arg data]]

................................................................................
[call method [cmd uri::direct] [arg vhosts] [arg patterns] [arg info] [arg body]]

[list_end]

 A rudimentary plugin that dispatches URLs from a dict
 data structure



[section {Class  ::httpd::reply.memchan}]
[list_begin definitions]

[call method [cmd output]]


[call method [cmd DoOutput]]


[call method [cmd close]]

[list_end]


[section {Class  ::httpd::plugin.local_memchan}]
[list_begin definitions]

[call method [cmd local_memchan] [arg command] ?[arg args]?]


................................................................................
 and pulls data directly from the reply_body data variable in the object

 Needed because memchan is bidirectional, and we can't seem to communicate that
 the server is one side of the link and the reply is another


[list_end]


[section AUTHORS]
Sean Woods

[vset CATEGORY network]
[include ../doctools2base/include/feedback.inc]

[manpage_end]








>







 







>







 







>




>











>







>







>







 







>










>







 







>







 







>









>







 







>













>





>




>







 







>













>







 







>






>


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
...
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
...
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
...
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
...
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
...
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
...
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
...
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903

 The working elements have been updated to operate as a TclOO object
 running with Tcl 8.6+. Global variables and hard coded tables are
 now resident with the object, allowing this server to be more easily
 embedded another program, as well as be adapted and extended to
 support the SCGI module



[section {Class  ::httpd::reply}]
[list_begin definitions]

[call method [cmd constructor] [arg ServerObj] ?[arg args]?]


................................................................................
     my puts [my html footer]
 	}
 }

 }]
 [list_end]



[section {Class  ::httpd::server}]
[list_begin definitions]

[call method [cmd constructor] [arg args] ?[arg port] [emph "auto"]? ?[arg myaddr] [emph "127.0.0.1"]? ?[arg string] [emph "auto"]? ?[arg name] [emph "auto"]? ?[arg doc_root] [emph ""]? ?[arg reverse_dns] [emph "0"]? ?[arg configuration_file] [emph ""]? ?[arg protocol] [emph "HTTP/1.1"]?]


................................................................................
[list_end]

 An httpd server with a template engine and a shim to insert URL domains.

 This class is the root object of the webserver. It is responsible
 for opening the socket and providing the initial connection negotiation.



[section {Class  ::httpd::server::dispatch}]

 Provide a backward compadible alias



[section {Class  ::httpd::content.redirect}]
[list_begin definitions]

[call method [cmd reset]]


[call method [cmd content]]

[list_end]


[section {Class  ::httpd::content.cache}]
[list_begin definitions]

[call method [cmd Dispatch]]

[list_end]


[section {Class  ::httpd::content.template}]
[list_begin definitions]

[call method [cmd content]]

[list_end]


[section {Class  ::httpd::content.file}]
[list_begin definitions]

[call method [cmd FileName]]


................................................................................

[list_end]

 Class to deliver Static content
 When utilized, this class is fed a local filename
 by the dispatcher



[section {Class  ::httpd::content.exec}]
[list_begin definitions]

[call method [cmd CgiExec] [arg execname] [arg script] [arg arglist]]


[call method [cmd Cgi_Executable] [arg script]]

[list_end]


[section {Class  ::httpd::content.proxy}]
[list_begin definitions]

[call method [cmd proxy_channel]]


................................................................................


[call method [cmd Dispatch]]

[list_end]

 Return data from an proxy process



[section {Class  ::httpd::content.cgi}]
[list_begin definitions]

[call method [cmd FileName]]

................................................................................

[call method [cmd DirectoryListing] [arg local_file]]

 For most CGI applications a directory list is vorboten


[list_end]


[section {Class  ::httpd::protocol.scgi}]
[list_begin definitions]

[call method [cmd EncodeStatus] [arg status]]

[list_end]

 Return data from an SCGI process



[section {Class  ::httpd::content.scgi}]
[list_begin definitions]

[call method [cmd scgi_info]]

................................................................................

[call method [cmd ProxyRequest] [arg chana] [arg chanb]]


[call method [cmd ProxyReply] [arg chana] [arg chanb] ?[arg args]?]

[list_end]


[section {Class  ::httpd::server.scgi}]
[list_begin definitions]

[call method [cmd debug] ?[arg args]?]


[call method [cmd Connect] [arg uuid] [arg sock] [arg ip]]

[list_end]

 Act as an  SCGI Server



[section {Class  ::httpd::content.websocket}]

 Upgrade a connection to a websocket



[section {Class  ::httpd::plugin}]

 httpd plugin template



[section {Class  ::httpd::plugin.dict_dispatch}]
[list_begin definitions]

[call method [cmd Dispatch_Dict] [arg data]]

................................................................................
[call method [cmd uri::direct] [arg vhosts] [arg patterns] [arg info] [arg body]]

[list_end]

 A rudimentary plugin that dispatches URLs from a dict
 data structure



[section {Class  ::httpd::reply.memchan}]
[list_begin definitions]

[call method [cmd output]]


[call method [cmd DoOutput]]


[call method [cmd close]]

[list_end]


[section {Class  ::httpd::plugin.local_memchan}]
[list_begin definitions]

[call method [cmd local_memchan] [arg command] ?[arg args]?]


................................................................................
 and pulls data directly from the reply_body data variable in the object

 Needed because memchan is bidirectional, and we can't seem to communicate that
 the server is one side of the link and the reply is another


[list_end]


[section AUTHORS]
Sean Woods

[vset CATEGORY network]
[include ../doctools2base/include/feedback.inc]

[manpage_end]

Changes to modules/practcl/build/build.tcl.

1
2
3



4
5
6

7
8
9
10
11
12
13
14
15
..
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
...
101
102
103
104
105
106
107







set srcdir [file dirname [file normalize [file join [pwd] [info script]]]]
set moddir [file dirname $srcdir]




set version 0.12
set tclversion 8.5
set module [file tail $moddir]


set fout [open [file join $moddir [file tail $module].tcl] w]
fconfigure $fout -translation lf
dict set map %module% $module
dict set map %version% $version
dict set map %tclversion% $tclversion
dict set map {    } {}
dict set map "\t" {    }

................................................................................
###
foreach {omod files} {
  httpwget wget.tcl
  clay {build/procs.tcl build/class.tcl build/object.tcl}
} {
  foreach fname $files {
    set file [file join $moddir .. $omod $fname]
    set fin [open $file r]
    puts $fout "###\n# START: [file join $omod $fname]\n###"
    puts $fout [read $fin]
    close $fin
    puts $fout "###\n# END: [file join $omod $fname]\n###"
  }
}

foreach file {
  setup.tcl
  buildutil.tcl
................................................................................
  {class subproject binary.tcl}
  {class subproject core.tcl}

  {class tool.tcl}

} {
  lappend loaded $file
  set fin [open [file join $srcdir {*}$file] r]
  puts $fout "###\n# START: [file join $file]\n###"
  puts $fout [read $fin]
  close $fin
  puts $fout "###\n# END: [file join $file]\n###"
}


# Provide some cleanup and our final package provide
puts $fout [string map $map {
namespace eval ::%module% {
................................................................................
set fout [open [file join $moddir pkgIndex.tcl] w]
fconfigure $fout -translation lf
puts $fout [string map $map {###
    if {![package vsatisfies [package provide Tcl] %tclversion%]} {return}
    package ifneeded %module% %version% [list source [file join $dir %module%.tcl]]
}]
close $fout










>
>
>



>

|







 







|
|
|
|







 







|
|
|
|







 







>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
..
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
set srcdir [file dirname [file normalize [file join [pwd] [info script]]]]
set moddir [file dirname $srcdir]

source [file join $moddir .. doctools docbuild.tcl]
::docbuild::object create AutoDoc

set version 0.12
set tclversion 8.5
set module [file tail $moddir]
set filename $module

set fout [open [file join $moddir $filename.tcl] w]
fconfigure $fout -translation lf
dict set map %module% $module
dict set map %version% $version
dict set map %tclversion% $tclversion
dict set map {    } {}
dict set map "\t" {    }

................................................................................
###
foreach {omod files} {
  httpwget wget.tcl
  clay {build/procs.tcl build/class.tcl build/object.tcl}
} {
  foreach fname $files {
    set file [file join $moddir .. $omod $fname]
    puts $fout "###\n# START: [file join $omod $fname]\n###"
    set content [::docbuild::cat [file join $moddir .. $omod $fname]]
    #AutoDoc scan_text $content
    puts $fout $content
    puts $fout "###\n# END: [file join $omod $fname]\n###"
  }
}

foreach file {
  setup.tcl
  buildutil.tcl
................................................................................
  {class subproject binary.tcl}
  {class subproject core.tcl}

  {class tool.tcl}

} {
  lappend loaded $file
  puts $fout "###\n# START: [file join $file]\n###"
  set content [::docbuild::cat [file join $srcdir {*}$file]]
  AutoDoc scan_text $content
  puts $fout $content
  puts $fout "###\n# END: [file join $file]\n###"
}


# Provide some cleanup and our final package provide
puts $fout [string map $map {
namespace eval ::%module% {
................................................................................
set fout [open [file join $moddir pkgIndex.tcl] w]
fconfigure $fout -translation lf
puts $fout [string map $map {###
    if {![package vsatisfies [package provide Tcl] %tclversion%]} {return}
    package ifneeded %module% %version% [list source [file join $dir %module%.tcl]]
}]
close $fout

set manout [open [file join $moddir $filename.man] w]
puts $manout [AutoDoc manpage \
  header [string map $map [::docbuild::cat [file join $srcdir manual.txt]]] \
  footer [string map $map [::docbuild::cat [file join $srcdir footer.txt]]] \
]
close $manout

Added modules/practcl/build/footer.txt.





>
>
1
2
[vset CATEGORY practcl]
[include ../doctools2base/include/feedback.inc]

Added modules/practcl/build/manual.txt.



























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
[comment {-*- %module% -*-}]
[vset VERSION %version%]
[manpage_begin practcl n [vset VERSION]]
[keywords practcl]
[copyright {2016-2018 Sean Woods <yoda@etoyoc.com>}]
[moddesc {The The Proper Rational API for C to Tool Command Language Module}]
[titledesc {The Practcl Module}]
[category {TclOO}]
[require TclOO 1.0]
[require practcl [vset VERSION]]
[description]
The Practcl module is a tool for integrating large modules for C API
Tcl code that requires custom Tcl types and TclOO objects.

Changes to modules/practcl/practcl.man.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21







































































































































22
23
24








































25
26

27
28
29
























































































































































































































































30
31
32
33
34
35
36

37
38
39
40

41
42
43
44

45
46
47
48

49
50


51
52
53
54
55
56

57
58













59
60































































































































































































































































































































































































































































































































































































































































61
62

63

[comment {-*- practcl -*-}]
[vset VERSION 0.11]
[manpage_begin practcl n [vset VERSION]]
[keywords practcl]
[copyright {2016-2018 Sean Woods <yoda@etoyoc.com>}]
[moddesc {The The Proper Rational API for C to Tool Command Language Module}]
[titledesc {The Practcl Module}]
[category {TclOO}]
[require TclOO 1.0]
[require practcl [vset VERSION]]
[description]
The Practcl module is a tool for integrating large modules for C API
Tcl code that requires custom Tcl types and TclOO objects.

[section COMMANDS]
[list_begin definitions]

[call [cmd CPUTS] [arg varname] [arg body] [opt [arg body]...]]
Appends blocks of text to a buffer. This command tries to reduce the number
of line breaks between bodies.








































































































































[call [cmd practcl::_isdirectory] [arg path]]
Returns true if [arg path] is a directory, using the test 









































[list_end]


[list_begin definitions]
[call [cmd practcl::object] [arg "parent"] [opt [arg "keyvaluelist"]]]

























































































































































































































































A generic Practcl object

[call [cmd practcl::library] [opt [arg "keyvaluelist"]]]

A Practcl object representing a library container

[call [cmd practcl::exe] [opt [arg "keyvaluelist"]]]


A Practcl object representing a wrapped executable

[call [cmd practcl::product] [arg "parent"] [opt [arg "keyvaluelist"]]]


A Practcl object representing a compiled product

[call [cmd practcl::cheader] [arg "parent"] [opt [arg "keyvaluelist"]]]


A Practcl object representing an externally generated c header

[call [cmd practcl::csource] [arg "parent"] [opt [arg "keyvaluelist"]]]


A Practcl object representing an externally generated c source file



[call [cmd practcl::module] [arg "parent"] [opt [arg "keyvaluelist"]]]

A Practcl object representing a dynamically generated C/H/Tcl suite

[call [cmd practcl::submodule] [arg "parent"] [opt [arg "keyvaluelist"]]]


A Practcl object representing a dynamically generated C/H/Tcl suite, subordinate to a module













[list_end]
































































































































































































































































































































































































































































































































































































































































[vset CATEGORY practcl]
[include ../doctools2base/include/feedback.inc]

[manpage_end]


|












|


|
|
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>

<

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

<

<

<
>

<

<
>

<

<
>

<

<
>

<
>
>

<

<

<
>

<
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>

>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453

454

455

456
457

458

459
460

461

462
463

464

465
466

467
468
469

470

471

472
473

474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
[comment {-*- practcl -*-}]
[vset VERSION 0.12]
[manpage_begin practcl n [vset VERSION]]
[keywords practcl]
[copyright {2016-2018 Sean Woods <yoda@etoyoc.com>}]
[moddesc {The The Proper Rational API for C to Tool Command Language Module}]
[titledesc {The Practcl Module}]
[category {TclOO}]
[require TclOO 1.0]
[require practcl [vset VERSION]]
[description]
The Practcl module is a tool for integrating large modules for C API
Tcl code that requires custom Tcl types and TclOO objects.

[section {Commands}]
[list_begin definitions]

[call proc [cmd practcl::debug] ?[arg args]?]
 Practcl
 An object oriented templating system for stamping out Tcl API calls to C


 Seek out Tcllib if it's available


 Build utility functions


 A command to do nothing. A handy way of
 negating an instruction without
 having to comment it completely out.
 It's also a handy attachment point for
 an object to be named later



[call proc [cmd practcl::doexec] ?[arg args]?]

 Drop in a static copy of Tcl



[call proc [cmd practcl::doexec_in] [arg path] ?[arg args]?]


[call proc [cmd practcl::dotclexec] ?[arg args]?]


[call proc [cmd practcl::domake] [arg path] ?[arg args]?]


[call proc [cmd practcl::domake.tcl] [arg path] ?[arg args]?]


[call proc [cmd practcl::fossil] [arg path] ?[arg args]?]


[call proc [cmd practcl::fossil_status] [arg dir]]


[call proc [cmd practcl::os]]


[call proc [cmd practcl::local_os]]


[call proc [cmd practcl::config.tcl] [arg path]]

 Detect local platform



[call proc [cmd practcl::read_configuration] [arg path]]


[call proc [cmd practcl::tcllib_require] [arg pkg] ?[arg args]?]

 Convert an MSYS path to a windows native path

 Try to load  a package, and failing that
 retrieve tcllib


[call proc [cmd practcl::platform::tcl_core_options] [arg os]]


[call proc [cmd practcl::platform::tk_core_options] [arg os]]


[call proc [cmd practcl::read_rc_file] [arg filename] ?[arg localdat] [emph ""]?]

 Read a stylized key/value list stored in a file



[call proc [cmd practcl::read_sh_subst] [arg line] [arg info]]

 topic: e71f3f61c348d56292011eec83e95f0aacc1c618
 description: Converts a XXX.sh file into a series of Tcl variables



[call proc [cmd practcl::read_sh_file] [arg filename] ?[arg localdat] [emph ""]?]

 topic: 03567140cca33c814664c7439570f669b9ab88e6



[call proc [cmd practcl::read_Config.sh] [arg filename]]

 A simpler form of read_sh_file tailored
 to pulling data from (tcl|tk)Config.sh



[call proc [cmd practcl::read_Makefile] [arg filename]]

 A simpler form of read_sh_file tailored
 to pulling data from a Makefile



[call proc [cmd practcl::cputs] [arg varname] ?[arg args]?]
 Append arguments to a buffer
 The command works like puts in that each call will also insert
 a line feed. Unlike puts, blank links in the interstitial are
 suppressed


[call proc [cmd practcl::tcl_to_c] [arg body]]


[call proc [cmd practcl::_tagblock] [arg text] ?[arg style] [emph "tcl"]? ?[arg note] [emph ""]?]


[call proc [cmd practcl::de_shell] [arg data]]


[call proc [cmd practcl::cat] [arg fname]]

 Bits stolen from fileutil



[call proc [cmd practcl::grep] [arg pattern] ?[arg files] [emph ""]?]


[call proc [cmd practcl::file_lexnormalize] [arg sp]]


[call proc [cmd practcl::file_relative] [arg base] [arg dst]]


[call proc [cmd practcl::log] [arg fname] [arg comment]]


[call proc [cmd practcl::_isdirectory] [arg name]]


 Installer tools



[call proc [cmd practcl::_pkgindex_directory] [arg path]]

 Return true if the pkgindex file contains
 any statement other than "package ifneeded"
 and/or if any package ifneeded loads a DLL



[call proc [cmd practcl::_pkgindex_path_subdir] [arg path]]


[call proc [cmd practcl::pkgindex_path] ?[arg args]?]

 Index all paths given as though they will end up in the same
 virtual file system



[call proc [cmd practcl::installDir] [arg d1] [arg d2]]


[call proc [cmd practcl::copyDir] [arg d1] [arg d2] ?[arg toplevel] [emph "1"]?]


[call proc [cmd practcl::trigger] ?[arg args]?]

 Backward compatible Make facilities
 These were used early in development and are consdiered deprecated



[call proc [cmd practcl::depends] ?[arg args]?]


[call proc [cmd practcl::target] [arg name] [arg info] ?[arg action] [emph ""]?]

[list_end]

[section {Class  ::practcl::metaclass}]
[list_begin definitions]


[call method [cmd _MorphPatterns]]


[call method [cmd define] [arg submethod] ?[arg args]?]


[call method [cmd graft] ?[arg args]?]


[call method [cmd initialize]]


[call method [cmd link] [arg command] ?[arg args]?]


[call method [cmd morph] [arg classname]]


[call method [cmd mixin] [arg slot] [arg classname]]


[call method [cmd organ] ?[arg args]?]


[call method [cmd script] [arg script]]


[call method [cmd select]]


[call method [cmd source] [arg filename]]

[list_end]


[section {Class  ::practcl::toolset}]
[list_begin definitions]

[call method [cmd config.sh]]

 find or fake a key/value list describing this project



[call method [cmd BuildDir] [arg PWD]]


[call method [cmd MakeDir] [arg srcdir]]


[call method [cmd read_configuration]]


[call method [cmd build-cflags] [arg PROJECT] [arg DEFS] [arg namevar] [arg versionvar] [arg defsvar]]
 method DEFS
 This method populates 4 variables:
 name - The name of the package
 version - The version of the package
 defs - C flags passed to the compiler
 includedir - A list of paths to feed to the compiler for finding headers



[call method [cmd critcl] ?[arg args]?]


[call method [cmd make-autodetect]]

[list_end]

 Ancestor-less class intended to be a mixin
 which defines a family of build related behaviors
 that are modified when targetting either gcc or msvc



[section {Class  ::practcl::toolset.gcc}]
[list_begin definitions]

[call method [cmd Autoconf]]


[call method [cmd BuildDir] [arg PWD]]


[call method [cmd ConfigureOpts]]


[call method [cmd MakeDir] [arg srcdir]]
 Detect what directory contains the Makefile template


[call method [cmd make-autodetect]]


[call method [cmd make-clean]]


[call method [cmd make-compile]]


[call method [cmd make-install] [arg DEST]]


[call method [cmd build-compile-sources] [arg PROJECT] [arg COMPILE] [arg CPPCOMPILE] [arg INCLUDES]]


[call method [cmd build-Makefile] [arg path] [arg PROJECT]]


[call method [cmd build-library] [arg outfile] [arg PROJECT]]

 Produce a static or dynamic library



[call method [cmd build-tclsh] [arg outfile] [arg PROJECT]]

 Produce a static executable


[list_end]


[section {Class  ::practcl::toolset.msvc}]
[list_begin definitions]

[call method [cmd BuildDir] [arg PWD]]
 MSVC always builds in the source directory


[call method [cmd make-autodetect]]
 Do nothing


[call method [cmd make-clean]]


[call method [cmd make-compile]]


[call method [cmd make-install] [arg DEST]]


[call method [cmd MakeDir] [arg srcdir]]
 Detect what directory contains the Makefile template


[call method [cmd NmakeOpts]]

[list_end]


[section {Class  ::practcl::make_obj}]
[list_begin definitions]

[call method [cmd constructor] [arg module_object] [arg name] [arg info] ?[arg action_body] [emph ""]?]


[call method [cmd do]]


[call method [cmd check]]


[call method [cmd output]]


[call method [cmd reset]]


[call method [cmd triggers]]

[list_end]


[section {Class  ::practcl::object}]
[list_begin definitions]

[call method [cmd constructor] [arg parent] ?[arg args]?]


[call method [cmd child] [arg method]]


[call method [cmd go]]

[list_end]


[section {Class  ::practcl::dynamic}]
[list_begin definitions]

[call method [cmd cstructure] [arg name] [arg definition] ?[arg argdat] [emph ""]?]

 Parser functions



[call method [cmd include] [arg header]]


[call method [cmd include_dir] ?[arg args]?]


[call method [cmd include_directory] ?[arg args]?]


[call method [cmd c_header] [arg body]]


[call method [cmd c_code] [arg body]]


[call method [cmd c_function] [arg header] [arg body] ?[arg info] [emph ""]?]


[call method [cmd c_tcloomethod] [arg name] [arg body] ?[arg arginfo] [emph ""]?]


[call method [cmd cmethod] [arg name] [arg body] ?[arg arginfo] [emph ""]?]
 Alias to classic name


[call method [cmd c_tclproc_nspace] [arg nspace]]


[call method [cmd c_tclcmd] [arg name] [arg body] ?[arg arginfo] [emph ""]?]


[call method [cmd c_tclproc_raw] [arg name] [arg body] ?[arg arginfo] [emph ""]?]
 Alias to classic name


[call method [cmd tcltype] [arg name] [arg argdat]]


[call method [cmd project-compile-products]]

 Module interactions



[call method [cmd implement] [arg path]]


[call method [cmd initialize]]

 Practcl internals






[call method [cmd linktype]]




[call method [cmd generate-cfile-constant]]




[call method [cmd generate-cfile-header]]




[call method [cmd generate-cfile-tclapi]]


 Generate code that provides implements Tcl API
 calls






[call method [cmd generate-loader-module]]


 Generate code that runs when the package/module is
 initialized into the interpreter



[call method [cmd Collate_Source] [arg CWD]]


[call method [cmd select]]
 Once an object marks itself as some
 flavor of dynamic, stop trying to morph
 it into something else

[list_end]

 Dynamic blocks do not generate their own .c files,
 instead the contribute to the amalgamation
 of the main library file



[section {Class  ::practcl::product}]
[list_begin definitions]

[call method [cmd code] [arg section] [arg body]]


[call method [cmd Collate_Source] [arg CWD]]


[call method [cmd project-compile-products]]


[call method [cmd generate-debug] ?[arg spaces] [emph ""]?]


[call method [cmd generate-cfile-constant]]


[call method [cmd generate-cfile-public-structure]]

 Populate const static data structures



[call method [cmd generate-cfile-header]]


[call method [cmd generate-cfile-global]]


[call method [cmd generate-cfile-private-typedef]]


[call method [cmd generate-cfile-private-structure]]


[call method [cmd generate-cfile-functions]]

 Generate code that provides subroutines called by
 Tcl API methods



[call method [cmd generate-cfile-tclapi]]

 Generate code that provides implements Tcl API
 calls



[call method [cmd generate-hfile-public-define]]


[call method [cmd generate-hfile-public-macro]]


[call method [cmd generate-hfile-public-typedef]]


[call method [cmd generate-hfile-public-structure]]


[call method [cmd generate-hfile-public-headers]]


[call method [cmd generate-hfile-public-function]]


[call method [cmd generate-hfile-public-includes]]


[call method [cmd generate-hfile-public-verbatim]]


[call method [cmd generate-loader-external]]


[call method [cmd generate-loader-module]]


[call method [cmd generate-stub-function]]


[call method [cmd IncludeAdd] [arg headervar] ?[arg args]?]


[call method [cmd generate-tcl-loader]]


[call method [cmd generate-tcl-pre]]

 This methods generates any Tcl script file
 which is required to pre-initialize the C library



[call method [cmd generate-tcl-post]]


[call method [cmd linktype]]


[call method [cmd Ofile] [arg filename]]


[call method [cmd project-static-packages]]

 Methods called by the master project



[call method [cmd toolset-include-directory]]

 Methods called by the toolset



[call method [cmd target] [arg method] ?[arg args]?]

[list_end]


[section {Class  ::practcl::product.cheader}]
[list_begin definitions]

[call method [cmd project-compile-products]]


[call method [cmd generate-loader-module]]

[list_end]

 Flesh out several trivial varieties of product



[section {Class  ::practcl::product.csource}]
[list_begin definitions]

[call method [cmd project-compile-products]]

[list_end]


[section {Class  ::practcl::product.clibrary}]
[list_begin definitions]

[call method [cmd linker-products] [arg configdict]]

[list_end]


[section {Class  ::practcl::product.dynamic}]
[list_begin definitions]

[call method [cmd initialize]]

[list_end]


[section {Class  ::practcl::product.critcl}]


[section {Class  ::practcl::module}]
[list_begin definitions]

[call method [cmd _MorphPatterns]]


[call method [cmd add] ?[arg args]?]


[call method [cmd install-headers] ?[arg args]?]


[call method [cmd make] [arg command] ?[arg args]?]

 Target handling



[call method [cmd child] [arg which]]


[call method [cmd generate-c]]

 This methods generates the contents of an amalgamated .c file
 which implements the loader for a batch of tools



[call method [cmd generate-h]]

 This methods generates the contents of an amalgamated .h file
 which describes the public API of this module



[call method [cmd generate-loader]]


[call method [cmd initialize]]


[call method [cmd implement] [arg path]]


[call method [cmd linktype]]

[list_end]

 In the end, all C code must be loaded into a module
 This will either be a dynamically loaded library implementing
 a tcl extension, or a compiled in segment of a custom shell/app



[section {Class  ::practcl::project}]
[list_begin definitions]

[call method [cmd _MorphPatterns]]


[call method [cmd constructor] ?[arg args]?]


[call method [cmd add_object] [arg object]]


[call method [cmd add_project] [arg pkg] [arg info] ?[arg oodefine] [emph ""]?]


[call method [cmd add_tool] [arg pkg] [arg info] ?[arg oodefine] [emph ""]?]


[call method [cmd build-tclcore]]


[call method [cmd child] [arg which]]


[call method [cmd linktype]]


[call method [cmd project] [arg pkg] ?[arg args]?]
 Exercise the methods of a sub-object


[call method [cmd tclcore]]


[call method [cmd tkcore]]


[call method [cmd tool] [arg pkg] ?[arg args]?]

[list_end]


[section {Class  ::practcl::library}]
[list_begin definitions]

[call method [cmd clean] [arg PATH]]


[call method [cmd project-compile-products]]


[call method [cmd go]]


[call method [cmd generate-decls] [arg pkgname] [arg path]]


[call method [cmd implement] [arg path]]


[call method [cmd generate-make] [arg path]]
 Backward compadible call


[call method [cmd linktype]]


[call method [cmd package-ifneeded] ?[arg args]?]
 Create a "package ifneeded"
 Args are a list of aliases for which this package will answer to


[call method [cmd shared_library] ?[arg filename] [emph ""]?]


[call method [cmd static_library] ?[arg filename] [emph ""]?]

[list_end]


[section {Class  ::practcl::tclkit}]
[list_begin definitions]

[call method [cmd build-tclkit_main] [arg PROJECT] [arg PKG_OBJS]]


[call method [cmd Collate_Source] [arg CWD]]


[call method [cmd wrap] [arg PWD] [arg exename] [arg vfspath] ?[arg args]?]
 Wrap an executable


[list_end]


[section {Class  ::practcl::distribution}]
[list_begin definitions]

[call method [cmd scm_info]]


[call method [cmd DistroMixIn]]


[call method [cmd Sandbox]]


[call method [cmd SrcDir]]


[call method [cmd ScmTag]]


[call method [cmd ScmClone]]


[call method [cmd ScmUnpack]]


[call method [cmd ScmUpdate]]


[call method [cmd Unpack]]

[list_end]

 Standalone class to manage code distribution
 This class is intended to be mixed into another class
 (Thus the lack of ancestors)



[section {Class  ::practcl::distribution.snapshot}]
[list_begin definitions]

[call method [cmd ScmUnpack]]

[list_end]


[section {Class  ::practcl::distribution.fossil}]
[list_begin definitions]

[call method [cmd scm_info]]


[call method [cmd ScmClone]]
 Clone the source


[call method [cmd ScmTag]]


[call method [cmd ScmUnpack]]


[call method [cmd ScmUpdate]]

[list_end]


[section {Class  ::practcl::distribution.git}]
[list_begin definitions]

[call method [cmd ScmTag]]


[call method [cmd ScmUnpack]]


[call method [cmd ScmUpdate]]

[list_end]


[section {Class  ::practcl::subproject}]
[list_begin definitions]

[call method [cmd _MorphPatterns]]


[call method [cmd BuildDir] [arg PWD]]


[call method [cmd child] [arg which]]


[call method [cmd compile]]


[call method [cmd go]]


[call method [cmd install] ?[arg args]?]
 Install project into the local build system


[call method [cmd linktype]]


[call method [cmd linker-products] [arg configdict]]


[call method [cmd linker-external] [arg configdict]]


[call method [cmd linker-extra] [arg configdict]]


[call method [cmd env-bootstrap]]

 Methods for packages/tools that can be downloaded
 possibly built and used internally by this Practcl
 process


 Load the facility into the interpreter



[call method [cmd env-exec]]

 Return a file path that exec can call



[call method [cmd env-install]]

 Install the tool into the local environment



[call method [cmd env-load]]

 Do whatever is necessary to get the tool
 into the local environment



[call method [cmd env-present]]

 Check if tool is available for load/already loaded



[call method [cmd sources]]


[call method [cmd update]]


[call method [cmd unpack]]

[list_end]


[section {Class  ::practcl::subproject.source}]
[list_begin definitions]

[call method [cmd env-bootstrap]]


[call method [cmd env-present]]


[call method [cmd linktype]]

[list_end]

 Trivial implementations


 A project which the kit compiles and integrates
 the source for itself



[section {Class  ::practcl::subproject.teapot}]
[list_begin definitions]

[call method [cmd env-bootstrap]]


[call method [cmd env-install]]


[call method [cmd env-present]]


[call method [cmd install] [arg DEST]]

[list_end]
 a copy from the teapot


[section {Class  ::practcl::subproject.kettle}]
[list_begin definitions]

[call method [cmd kettle] [arg path] ?[arg args]?]


[call method [cmd install] [arg DEST]]

[list_end]


[section {Class  ::practcl::subproject.critcl}]
[list_begin definitions]

[call method [cmd install] [arg DEST]]

[list_end]


[section {Class  ::practcl::subproject.sak}]
[list_begin definitions]

[call method [cmd env-bootstrap]]


[call method [cmd env-install]]


[call method [cmd env-present]]


[call method [cmd install] [arg DEST]]


[call method [cmd install-module] [arg DEST] ?[arg args]?]

[list_end]


[section {Class  ::practcl::subproject.binary}]
[list_begin definitions]

[call method [cmd clean]]


[call method [cmd env-install]]


[call method [cmd project-compile-products]]


[call method [cmd ComputeInstall]]


[call method [cmd go]]


[call method [cmd linker-products] [arg configdict]]


[call method [cmd project-static-packages]]


[call method [cmd BuildDir] [arg PWD]]


[call method [cmd compile]]


[call method [cmd Configure]]


[call method [cmd install] [arg DEST]]

[list_end]

 A binary package



[section {Class  ::practcl::subproject.tea}]


[section {Class  ::practcl::subproject.library}]
[list_begin definitions]

[call method [cmd install] [arg DEST]]

[list_end]


[section {Class  ::practcl::subproject.external}]
[list_begin definitions]

[call method [cmd install] [arg DEST]]

[list_end]
 An external library


[section {Class  ::practcl::subproject.core}]
[list_begin definitions]

[call method [cmd env-bootstrap]]


[call method [cmd env-present]]


[call method [cmd env-install]]


[call method [cmd go]]


[call method [cmd linktype]]

[list_end]


[vset CATEGORY practcl]
[include ../doctools2base/include/feedback.inc]

[manpage_end]

Changes to modules/practcl/practcl.tcl.

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
...
395
396
397
398
399
400
401

402
403
404
405
406
407
408
...
426
427
428
429
430
431
432
433













434
435










436


437
438
439
440
441
442
443
444
445
446
...
476
477
478
479
480
481
482
483
484
485

486
487
488
489
490
491
492
493
494
495
496
497
498









499
500
501
502
503
504
505
...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
...
557
558
559
560
561
562
563

564
565
566
567
568
569
570
...
596
597
598
599
600
601
602
603
604

605
606
607
608
609
610
611
...
652
653
654
655
656
657
658
659
660
661
662
663
664
665



666
667
668
669
670
671
672
...
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
...
733
734
735
736
737
738
739









740
741
742
743
744
745
746
747
748
749
750

751
752
753
754
755
756
757
...
764
765
766
767
768
769
770

771
772
773
774
775
776
777
778
779
780
781
782













































































783
784
785
786
787
788
789
....
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
....
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
....
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
....
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
....
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
....
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
....
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
....
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
....
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
....
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
....
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192

###
# END: httpwget/wget.tcl
###
###
# START: clay/build/procs.tcl
###
::namespace eval ::clay {}
set ::clay::trace 0

###
# Global utilities
###
if {[info commands ::ladd] eq {}} {
  proc ladd {varname args} {
................................................................................
  }
  return $args
}

proc ::clay::args_to_options args {
  set result {}
  foreach {var val} [args_to_dict {*}$args] {
    lappend result [string trimright [string trimleft $var -] :] $val
  }
  return $result
}

proc ::clay::dictmerge {varname args} {
  upvar 1 $varname result
  if {![info exists result]} {
................................................................................
}

proc ::clay::uuid_generate args {
  return [uuid::uuid generate]
}

namespace eval ::clay {

  variable core_classes {::oo::class ::oo::object}
}

###
# END: clay/build/procs.tcl
###
###
................................................................................
        return [dict exists $clay {*}$path]
      }
      dump {
        return $clay
      }
      getnull -
      get {
        if {[llength $args]==0} {













          return $clay
        }










        if {![dict exists $clay {*}$args]} {


          return {}
        }
        tailcall dict get $clay {*}$args
      }
      merge {
        foreach arg $args {
          ::clay::dictmerge clay {*}$arg
        }
      }
      search {
................................................................................
  # format: markdown
  # description:
  # The *clay* method allows an object access
  # to a combination of its own clay data as
  # well as to that of its class
  ###
  method clay {submethod args} {
    my variable clay claycache clayorder
    if {![info exists clay]} {set clay {}}
    if {![info exists claycache]} {set claycache {}}

    if {![info exists clayorder] || [llength $clayorder]==0} {
      set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]]
    }
    if {$::clay::trace > 1} {
      puts [list [info object class [self]] / [self] clay $submethod {*}$args]
    }
    switch $submethod {
      ancestors {
        return $clayorder
      }
      cget {
        # Leaf searches return one data field at a time
        # Search in our local dict









        if {[dict exists $clay {*}$args]} {
          return [dict get $clay {*}$args]
        }
        # Search in our local cache
        if {[dict exists $claycache {*}$args]} {
          return [dict get $claycache {*}$args]
        }
................................................................................
            return $value
          }
          if {[$class clay exists const/ {*}$args]} {
            set value [$class clay get const/ {*}$args]
            dict set claycache {*}$args $value
            return $value
          }
          if {[llength $args]==1} {
            set field [lindex $args 0]
            if {[$class clay exists public/ option/ ${field}/ default]} {
              set value [$class clay get public/ option/ ${field}/ default]
              dict set claycache {*}$args $value
              return $value
            }
          }
        }
        return {}
      }
      delegate {
        if {![dict exists $clay delegate/ <class>]} {
          dict set clay delegate/ <class> [info object class [self]]
        }
................................................................................
      dump {
        # Do a full dump of clay data
        set result $clay
        # Search in the in our list of classes for an answer
        foreach class $clayorder {
          ::clay::dictmerge result [$class clay dump]
        }

        return $result
      }
      ensemble_map {
        set ensemble [lindex $args 0]
        my variable claycache
        set mensemble [string trim $ensemble :/]/
        if {[dict exists $claycache method_ensemble/ $mensemble]} {
................................................................................
          } elseif {
            append buffer "my $thisline" \n
          }
          set thisline {}
        }
        eval $buffer
      }
      evolve {
        my Evolve

      }
      exists {
        # Leaf searches return one data field at a time
        # Search in our local dict
        if {[dict exists $clay {*}$args]} {
          return 1
        }
................................................................................
              return $value
            }
          }
        } else {
          set result {}
          # Leaf searches return one data field at a time
          # Search in our local dict
          if {[dict exists $clay {*}$args]} {
            set result [dict get $clay {*}$args]
          }
          # Search in the in our list of classes for an answer
          foreach class $clayorder {
            ::clay::dictmerge result [$class clay get {*}$args]
          }



          return $result
        }
      }
      leaf {
        # Leaf searches return one data field at a time
        # Search in our local dict
        if {[dict exists $clay {*}$args]} {
................................................................................
        set newmixin {}
        foreach item $args {
          lappend newmixin ::[string trimleft $item :]
        }
        set newmap $args
        foreach class $prior {
          if {$class ni $newmixin} {
            set script [$class clay search mixin/ unmap-script]
            if {[string length $script]} {
              if {[catch $script err errdat]} {
                puts stderr "[self] MIXIN ERROR POPPING $class:\n[dict get $errdat -errorinfo]"
              }
            }
          }
        }
        ::oo::objdefine [self] mixin {*}$args
        ###
        # Build a compsite map of all ensembles defined by the object's current
        # class as well as all of the classes being mixed in
        ###
        my Evolve
        foreach class $newmixin {
          if {$class ni $prior} {
            set script [$class clay search mixin/ map-script]
            if {[string length $script]} {
              if {[catch $script err errdat]} {
                puts stderr "[self] MIXIN ERROR PUSHING $class:\n[dict get $errdat -errorinfo]"
              }
            }
          }
        }
................................................................................
              puts stderr "[self] MIXIN ERROR PEEKING $class:\n[dict get $errdat -errorinfo]"
            }
            break
          }
        }
      }
      mixinmap {









        foreach {slot classes} $args {
          dict set clay mixin $slot $classes
        }
        set claycache {}
        set classlist {}
        foreach {item class} [my clay get mixin] {
          if {$class ne {}} {
            lappend classlist $class
          }
        }
        my clay mixin {*}$classlist

      }
      provenance {
        if {[dict exists $clay {*}$args]} {
          return self
        }
        foreach class $clayorder {
          if {[$class clay exists {*}$args]} {
................................................................................
        set clay [lindex $args 0]
      }
      source {
        source [lindex $args 0]
      }
      set {
        #puts [list [self] clay SET {*}$args]

        ::clay::dictmerge clay {*}$args
      }
      default {
        dict $submethod clay {*}$args
      }
    }
  }

  ###
  # React to a mixin
  ###
  method Evolve {} {}













































































}


###
# END: clay/build/object.tcl
###
###
................................................................................
oo::class create ::practcl::toolset {
  ###
  # find or fake a key/value list describing this project
  ###
  method config.sh {} {
    return [my read_configuration]
  }

  method BuildDir {PWD} {
    set name [my define get name]
    set debug [my define get debug 0]
    if {[my <project> define get LOCAL 0]} {
      return [my define get builddir [file join $PWD local $name]]
    }
    if {$debug} {
      return [my define get builddir [file join $PWD debug $name]]
    } else {
      return [my define get builddir [file join $PWD pkg $name]]
    }
  }

  method MakeDir {srcdir} {
    return $srcdir
  }

  method read_configuration {} {
    my variable conf_result
    if {[info exists conf_result]} {
      return $conf_result
    }
    set result {}
    set name [my define get name]
................................................................................
    }
    set srcdir [my SourceRoot]
    set PWD [pwd]
    cd $srcdir
    ::practcl::dotclexec $critcl {*}$args
    cd $PWD
  }

  method make-autodetect {} {}
}


oo::objdefine ::practcl::toolset {


................................................................................

  # MSVC always builds in the source directory
  method BuildDir {PWD} {
    set srcdir [my define get srcdir]
    return $srcdir
  }


  # Do nothing
  method make-autodetect {} {
  }

  method make-clean {} {
    set PWD [pwd]
    set srcdir [my define get srcdir]
    cd $srcdir
    catch {::practcl::doexec nmake -f makefile.vc clean}
    cd $PWD
  }

  method make-compile {} {
    set srcdir [my define get srcdir]
    if {[my define get static 1]} {
      puts "BUILDING Static $name $srcdir"
    } else {
      puts "BUILDING Dynamic $name $srcdir"
    }
................................................................................
        cd [file join $srcdir win]
        ::practcl::doexec nmake -f makefile.vc INSTALLDIR=[my <project> define get installdir]  {*}[my NmakeOpts] release
      } else {
        error "No make.tcl or makefile.vc found for project $name"
      }
    }
  }

  method make-install DEST {
    set PWD [pwd]
    set srcdir [my define get srcdir]
    cd $srcdir
    if {$DEST eq {}} {
      error "No destination given"
    }
................................................................................
      } else {
        puts "[self] VFS INSTALL $DEST"
        ::practcl::doexec nmake -f makefile.vc INSTALLDIR=$DEST {*}[my NmakeOpts] install
      }
    }
    cd $PWD
  }

  # Detect what directory contains the Makefile template
  method MakeDir {srcdir} {
    set localsrcdir $srcdir
    if {[file exists [file join $srcdir generic]]} {
      my define add include_dir [file join $srcdir generic]
    }
    if {[file exists [file join $srcdir win]]} {
................................................................................
       my define add include_dir [file join $srcdir win]
    }
    if {[file exists [file join $srcdir makefile.vc]]} {
      set localsrcdir [file join $srcdir win]
    }
    return $localsrcdir
  }

  method NmakeOpts {} {
    set opts {}
    set builddir [file normalize [my define get builddir]]

    if {[my <project> define exists tclsrcdir]} {
      ###
      # On Windows we are probably running under MSYS, which doesn't deal with
................................................................................
        if {$filename ne {} && ![file exists $filename]} {
          set needs_make 1
        }
      }
    }
    return $needs_make
  }

  method output {} {
    set result {}
    set filename [my define get filename]
    if {$filename ne {}} {
      lappend result $filename
    }
    foreach filename [my define get files] {
................................................................................

  method reset {} {
    my variable triggered domake needs_make
    set triggerd 0
    set domake 0
    set needs_make 0
  }

  method triggers {} {
    my variable triggered domake define
    if {$triggered} {
      return $domake
    }
    set triggered 1
    set make_objects [my <module> make objects]
................................................................................
    foreach {f v} $argdat {
      dict set cstruct $name $f $v
    }
    if {![dict exists $cstruct $name public]} {
      dict set cstruct $name public 1
    }
  }

  method include header {
    my define add include $header
  }

  method include_dir args {
    my define add include_dir {*}$args
  }
................................................................................
      scm  None
      hash {}
      maxdate {}
      tags {}
      isodate {}
    }
  }

  method DistroMixIn {} {
    my define set scm none
  }

  method Sandbox {} {
    if {[my define exists sandbox]} {
      return [my define get sandbox]
................................................................................
    set info [next]
    dict set info scm fossil
    foreach {field value} [::practcl::fossil_status [my define get srcdir]] {
      dict set info $field $value
    }
    return $info
  }

  # Clone the source
  method ScmClone  {} {
    set srcdir [my SrcDir]
    if {[file exists [file join $srcdir .fslckout]]} {
      return
    }
    if {[file exists [file join $srcdir _FOSSIL_]]} {







|







 







|







 







>







 







|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
|
>
>
|

<







 







|


>



<
<
<







>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<
<







 







>







 







|
|
>







 







<
<
|

|


>
>
>







 







|












|


|







 







>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
>







 







>











|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|












|



|







 







|







 







|



|







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
...
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
...
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464

465
466
467
468
469
470
471
...
501
502
503
504
505
506
507
508
509
510
511
512
513
514



515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
...
543
544
545
546
547
548
549








550
551
552
553
554
555
556
...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
...
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
...
678
679
680
681
682
683
684


685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
...
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
...
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
...
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
....
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
....
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
....
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
....
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
....
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
....
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
....
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
....
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
....
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
....
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
....
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307

###
# END: httpwget/wget.tcl
###
###
# START: clay/build/procs.tcl
###

set ::clay::trace 0

###
# Global utilities
###
if {[info commands ::ladd] eq {}} {
  proc ladd {varname args} {
................................................................................
  }
  return $args
}

proc ::clay::args_to_options args {
  set result {}
  foreach {var val} [args_to_dict {*}$args] {
    lappend result [string trim $var -:] $val
  }
  return $result
}

proc ::clay::dictmerge {varname args} {
  upvar 1 $varname result
  if {![info exists result]} {
................................................................................
}

proc ::clay::uuid_generate args {
  return [uuid::uuid generate]
}

namespace eval ::clay {
  variable option_class {}
  variable core_classes {::oo::class ::oo::object}
}

###
# END: clay/build/procs.tcl
###
###
................................................................................
        return [dict exists $clay {*}$path]
      }
      dump {
        return $clay
      }
      getnull -
      get {
        set path $args
        set leaf [expr {[string index [lindex $path end] end] ne "/"}]
        set clayorder [::clay::ancestors [self]]
        #puts [list [self] clay get {*}$path (leaf: $leaf)]
        if {$leaf} {
          #puts [list EXISTS: (clay) [dict exists $clay {*}$path]]
          if {[dict exists $clay {*}$path]} {
            return [dict get $clay {*}$path]
          }
          #puts [list Search in the in our list of classes for an answer]
          foreach class $clayorder {
            if {$class eq [self]} continue
            if {[$class clay exists {*}$path]} {
              set value [$class clay get {*}$path]
              return $value
            }
          }
        } else {
          set result {}
          # Leaf searches return one data field at a time
          # Search in our local dict
          # Search in the in our list of classes for an answer
          foreach class [lreverse $clayorder] {
            if {$class eq [self]} continue
            ::clay::dictmerge result [$class clay get {*}$path]
          }
          if {[dict exists $clay {*}$path]} {
            ::clay::dictmerge result [dict get $clay {*}$path]
          }
          return $result
        }

      }
      merge {
        foreach arg $args {
          ::clay::dictmerge clay {*}$arg
        }
      }
      search {
................................................................................
  # format: markdown
  # description:
  # The *clay* method allows an object access
  # to a combination of its own clay data as
  # well as to that of its class
  ###
  method clay {submethod args} {
    my variable clay claycache clayorder config option_canonical
    if {![info exists clay]} {set clay {}}
    if {![info exists claycache]} {set claycache {}}
    if {![info exists config]} {set config {}}
    if {![info exists clayorder] || [llength $clayorder]==0} {
      set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]]
    }



    switch $submethod {
      ancestors {
        return $clayorder
      }
      cget {
        # Leaf searches return one data field at a time
        # Search in our local dict
        if {[llength $args]==1} {
          set field [string trim [lindex $args 0] -:/]
          if {[info exists option_canonical($field)]} {
            set field $option_canonical($field)
          }
          if {[dict exists $config $field]} {
            return [dict get $config $field]
          }
        }
        if {[dict exists $clay {*}$args]} {
          return [dict get $clay {*}$args]
        }
        # Search in our local cache
        if {[dict exists $claycache {*}$args]} {
          return [dict get $claycache {*}$args]
        }
................................................................................
            return $value
          }
          if {[$class clay exists const/ {*}$args]} {
            set value [$class clay get const/ {*}$args]
            dict set claycache {*}$args $value
            return $value
          }








        }
        return {}
      }
      delegate {
        if {![dict exists $clay delegate/ <class>]} {
          dict set clay delegate/ <class> [info object class [self]]
        }
................................................................................
      dump {
        # Do a full dump of clay data
        set result $clay
        # Search in the in our list of classes for an answer
        foreach class $clayorder {
          ::clay::dictmerge result [$class clay dump]
        }
        ::clay::dictmerge result $clay
        return $result
      }
      ensemble_map {
        set ensemble [lindex $args 0]
        my variable claycache
        set mensemble [string trim $ensemble :/]/
        if {[dict exists $claycache method_ensemble/ $mensemble]} {
................................................................................
          } elseif {
            append buffer "my $thisline" \n
          }
          set thisline {}
        }
        eval $buffer
      }
      evolve -
      initialize {
        my InitializePublic
      }
      exists {
        # Leaf searches return one data field at a time
        # Search in our local dict
        if {[dict exists $clay {*}$args]} {
          return 1
        }
................................................................................
              return $value
            }
          }
        } else {
          set result {}
          # Leaf searches return one data field at a time
          # Search in our local dict



          # Search in the in our list of classes for an answer
          foreach class [lreverse $clayorder] {
            ::clay::dictmerge result [$class clay get {*}$args]
          }
          if {[dict exists $clay {*}$args]} {
            ::clay::dictmerge result [dict get $clay {*}$args]
          }
          return $result
        }
      }
      leaf {
        # Leaf searches return one data field at a time
        # Search in our local dict
        if {[dict exists $clay {*}$args]} {
................................................................................
        set newmixin {}
        foreach item $args {
          lappend newmixin ::[string trimleft $item :]
        }
        set newmap $args
        foreach class $prior {
          if {$class ni $newmixin} {
            set script [$class clay get mixin/ unmap-script]
            if {[string length $script]} {
              if {[catch $script err errdat]} {
                puts stderr "[self] MIXIN ERROR POPPING $class:\n[dict get $errdat -errorinfo]"
              }
            }
          }
        }
        ::oo::objdefine [self] mixin {*}$args
        ###
        # Build a compsite map of all ensembles defined by the object's current
        # class as well as all of the classes being mixed in
        ###
        my InitializePublic
        foreach class $newmixin {
          if {$class ni $prior} {
            set script [$class clay get mixin/ map-script]
            if {[string length $script]} {
              if {[catch $script err errdat]} {
                puts stderr "[self] MIXIN ERROR PUSHING $class:\n[dict get $errdat -errorinfo]"
              }
            }
          }
        }
................................................................................
              puts stderr "[self] MIXIN ERROR PEEKING $class:\n[dict get $errdat -errorinfo]"
            }
            break
          }
        }
      }
      mixinmap {
        my variable clay
        if {![dict exists $clay mixin]} {
          dict set clay mixin {}
        }
        if {[llength $args]==0} {
          return [dict get $clay mixin]
        } elseif {[llength $args]==1} {
          return [dict getnull $clay mixin [lindex $args 0]]
        } else {
          foreach {slot classes} $args {
            dict set clay mixin $slot $classes
          }
          set claycache {}
          set classlist {}
          foreach {item class} [dict get $clay mixin] {
            if {$class ne {}} {
              lappend classlist $class
            }
          }
          my clay mixin {*}$classlist
        }
      }
      provenance {
        if {[dict exists $clay {*}$args]} {
          return self
        }
        foreach class $clayorder {
          if {[$class clay exists {*}$args]} {
................................................................................
        set clay [lindex $args 0]
      }
      source {
        source [lindex $args 0]
      }
      set {
        #puts [list [self] clay SET {*}$args]
        set claycache {}
        ::clay::dictmerge clay {*}$args
      }
      default {
        dict $submethod clay {*}$args
      }
    }
  }

  ###
  # React to a mixin
  ###
  method InitializePublic {} {
    my variable clayorder clay claycache config option_canonical
    set claycache {}
    set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]]
    if {![info exists config]} {
      set config {}
    }
    foreach {var value} [my clay get variable/] {
      set var [string trim $var :/]
      if { $var in {clay} } continue
      my variable $var
      if {![info exists $var]} {
        if {$::clay::trace>2} {puts [list initialize variable $var $value]}
        set $var $value
      }
    }
    foreach {var value} [my clay get dict/] {
      set var [string trim $var :/]
      my variable $var
      if {![info exists $var]} {
        set $var {}
      }
      foreach {f v} $value {
        if {![dict exists ${var} $f]} {
          if {$::clay::trace>2} {puts [list initialize dict $var $f $v]}
          dict set ${var} $f $v
        }
      }
    }
    foreach {var value} [my clay get dict/] {
      set var [string trim $var :/]
      foreach {f v} [my clay get $var/] {
        if {![dict exists ${var} $f]} {
          if {$::clay::trace>2} {puts [list initialize dict (from const) $var $f $v]}
          dict set ${var} $f $v
        }
      }
    }
    foreach {var value} [my clay get array/] {
      set var [string trim $var :/]
      if { $var eq {clay} } continue
      my variable $var
      if {![info exists $var]} { array set $var {} }
      foreach {f v} $value {
        if {![array exists ${var}($f)]} {
          if {$::clay::trace>2} {puts [list initialize array $var\($f\) $v]}
          set ${var}($f) $v
        }
      }
    }
    foreach {var value} [my clay get array/] {
      set var [string trim $var :/]
      foreach {f v} [my clay get $var/] {
        if {![array exists ${var}($f)]} {
          if {$::clay::trace>2} {puts [list initialize array (from const) $var\($f\) $v]}
          set ${var}($f) $v
        }
      }
    }
    foreach {field info} [my clay get option/] {
      set field [string trim $field -/:]
      foreach alias [dict getnull $info aliases] {
        set option_canonical($alias) $field
      }
      if {[dict exists $config $field]} continue
      set getcmd [dict getnull $info default-command]
      if {$getcmd ne {}} {
        set value [{*}[string map [list %field% $field %self% [namespace which my]] $getcmd]]
      } else {
        set value [dict getnull $info default]
      }
      dict set config $field $value
      set setcmd [dict getnull $info set-command]
      if {$setcmd ne {}} {
        {*}[string map [list %field% [list $field] %value% [list $value] %self% [namespace which my]] $setcmd]
      }
    }
  }
}


###
# END: clay/build/object.tcl
###
###
................................................................................
oo::class create ::practcl::toolset {
  ###
  # find or fake a key/value list describing this project
  ###
  method config.sh {} {
    return [my read_configuration]
  }
  
  method BuildDir {PWD} {
    set name [my define get name]
    set debug [my define get debug 0]
    if {[my <project> define get LOCAL 0]} {
      return [my define get builddir [file join $PWD local $name]]
    }
    if {$debug} {
      return [my define get builddir [file join $PWD debug $name]]
    } else {
      return [my define get builddir [file join $PWD pkg $name]]
    }
  }
  
  method MakeDir {srcdir} {
    return $srcdir
  }
  
  method read_configuration {} {
    my variable conf_result
    if {[info exists conf_result]} {
      return $conf_result
    }
    set result {}
    set name [my define get name]
................................................................................
    }
    set srcdir [my SourceRoot]
    set PWD [pwd]
    cd $srcdir
    ::practcl::dotclexec $critcl {*}$args
    cd $PWD
  }
  
  method make-autodetect {} {}
}


oo::objdefine ::practcl::toolset {


................................................................................

  # MSVC always builds in the source directory
  method BuildDir {PWD} {
    set srcdir [my define get srcdir]
    return $srcdir
  }

  
  # Do nothing
  method make-autodetect {} {
  }
  
  method make-clean {} {
    set PWD [pwd]
    set srcdir [my define get srcdir]
    cd $srcdir
    catch {::practcl::doexec nmake -f makefile.vc clean}
    cd $PWD
  }
  
  method make-compile {} {
    set srcdir [my define get srcdir]
    if {[my define get static 1]} {
      puts "BUILDING Static $name $srcdir"
    } else {
      puts "BUILDING Dynamic $name $srcdir"
    }
................................................................................
        cd [file join $srcdir win]
        ::practcl::doexec nmake -f makefile.vc INSTALLDIR=[my <project> define get installdir]  {*}[my NmakeOpts] release
      } else {
        error "No make.tcl or makefile.vc found for project $name"
      }
    }
  }
  
  method make-install DEST {
    set PWD [pwd]
    set srcdir [my define get srcdir]
    cd $srcdir
    if {$DEST eq {}} {
      error "No destination given"
    }
................................................................................
      } else {
        puts "[self] VFS INSTALL $DEST"
        ::practcl::doexec nmake -f makefile.vc INSTALLDIR=$DEST {*}[my NmakeOpts] install
      }
    }
    cd $PWD
  }
  
  # Detect what directory contains the Makefile template
  method MakeDir {srcdir} {
    set localsrcdir $srcdir
    if {[file exists [file join $srcdir generic]]} {
      my define add include_dir [file join $srcdir generic]
    }
    if {[file exists [file join $srcdir win]]} {
................................................................................
       my define add include_dir [file join $srcdir win]
    }
    if {[file exists [file join $srcdir makefile.vc]]} {
      set localsrcdir [file join $srcdir win]
    }
    return $localsrcdir
  }
  
  method NmakeOpts {} {
    set opts {}
    set builddir [file normalize [my define get builddir]]

    if {[my <project> define exists tclsrcdir]} {
      ###
      # On Windows we are probably running under MSYS, which doesn't deal with
................................................................................
        if {$filename ne {} && ![file exists $filename]} {
          set needs_make 1
        }
      }
    }
    return $needs_make
  }
  
  method output {} {
    set result {}
    set filename [my define get filename]
    if {$filename ne {}} {
      lappend result $filename
    }
    foreach filename [my define get files] {
................................................................................

  method reset {} {
    my variable triggered domake needs_make
    set triggerd 0
    set domake 0
    set needs_make 0
  }
  
  method triggers {} {
    my variable triggered domake define
    if {$triggered} {
      return $domake
    }
    set triggered 1
    set make_objects [my <module> make objects]
................................................................................
    foreach {f v} $argdat {
      dict set cstruct $name $f $v
    }
    if {![dict exists $cstruct $name public]} {
      dict set cstruct $name public 1
    }
  }
  
  method include header {
    my define add include $header
  }

  method include_dir args {
    my define add include_dir {*}$args
  }
................................................................................
      scm  None
      hash {}
      maxdate {}
      tags {}
      isodate {}
    }
  }
  
  method DistroMixIn {} {
    my define set scm none
  }

  method Sandbox {} {
    if {[my define exists sandbox]} {
      return [my define get sandbox]
................................................................................
    set info [next]
    dict set info scm fossil
    foreach {field value} [::practcl::fossil_status [my define get srcdir]] {
      dict set info $field $value
    }
    return $info
  }
  
  # Clone the source
  method ScmClone  {} {
    set srcdir [my SrcDir]
    if {[file exists [file join $srcdir .fslckout]]} {
      return
    }
    if {[file exists [file join $srcdir _FOSSIL_]]} {