Tcl Library Source Code

Check-in [1fd28c318f]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2018 Conference, Houston/TX, US, Oct 15-19
Send your abstracts to tclconference@googlegroups.com
or submit via the online form by Aug 20.

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

Overview
Comment:More refinements to the docbuild tool. Updated documentation for httpd and practcl
Timelines: family | ancestors | descendants | both | hypnotoad
Files: files | file ages | folders
SHA3-256:1fd28c318f1eaf57e66fed848ecf28df078f0cd5f77075ed43ffbe66c649ea10
User & Date: hypnotoad 2018-09-16 09:22:45
Context
2018-09-17
02:21
Moved the new module autodoc tool to the clay module. Added documentatation capture to the build scripts of clay and practcl Updated the httpd module to get it's doctool parts from clay. check-in: 22a614e7a5 user: hypnotoad tags: hypnotoad
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
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to modules/doctools/docbuild.tcl.

54
55
56
57
58
59
60
61











62
63










































64
65




66

67
68
69
70
71
72
73
..
76
77
78
79
80
81
82




83
84
85
86
87
88
89
..
91
92
93
94
95
96
97



















98
99
100
101
102
103
104
...
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
...
170
171
172
173
174
175
176








177
178
179
180
181
182
183
...
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
...
285
286
287
288
289
290
291

292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
        }
      }
    }
    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 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 {
................................................................................
          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]
................................................................................
      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"
................................................................................
          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 {}
................................................................................
      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 {}
................................................................................
    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







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


>
>
>
>
|
>







 







>
>
>
>







 







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







 







|
<
<
<
<
<
<




>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>







 







|






|









|

|





|
|








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

>










|








|

|





|

|





|
|



<
<
|







 







>






|
|







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
...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
...
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
...
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
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
...
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
...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
        }
      }
    }
    return $result
  }

  method comment block {
    set count 0
    set field description
    set result [dict create description {}]
    foreach line [split $block \n] {
      set line [string trim $line]
      set fwidx [string first " " $line]
      set firstword [string range $line 0 [expr {$fwidx-1}]]
      if {[string index $firstword end] eq ":"} {
        set field [string trim $firstword -]
        switch $field {
          desc {
            set field description
          }
        }
        set line [string range $line [expr {$fwidx+1}] end]
      }
      dict append result $field "$line\n"
    }
    return $result
  }

  ###
  # Process an oo::objdefine call that modifies the class object
  # itself
  ####
  method keyword.Class {resultvar commentblock name body} {
    upvar 1 $resultvar result
    set name [string trim $name :]
    if {[dict exists $result class $name]} {
      set info [dict get $result class $name]
    } else {
      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 {
        method -
        Ensemble {
          my keyword.class_method info $commentblock  {*}[lrange $thisline 1 end-1]
          set commentblock {}
        }
      }
      set thisline {}
    }
    dict set result class $name $info
  }

  method keyword.class {resultvar commentblock name body} {
    upvar 1 $resultvar result
    set name [string trim $name :]
    if {[dict exists $result class $name]} {
      set info [dict get $result class $name]
    } else {
      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 cmd [string trim [lindex $thisline 0] ":"]
      switch $cmd {
        superclass {
          dict set info ancestors [lrange $thisline 1 end]
          set commentblock {}
        }
        class_method {
          my keyword.class_method info $commentblock  {*}[lrange $thisline 1 end-1]
          set commentblock {}
        }
        destructor -
        constructor {
          my keyword.method info $commentblock {*}[lrange $thisline 0 end-1]
          set commentblock {}
        }
        method -
        Ensemble {
................................................................................
          set commentblock {}
        }
      }
      set thisline {}
    }
    dict set result class $name $info
  }

  method keyword.class_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 class_method [string trim $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]
................................................................................
      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 -






        proc {
          set procinfo [my keyword.proc $commentblock {*}[lrange $thisline 1 end]]
          dict set info proc [string trim [lindex $thisline 1] :] $procinfo
          set commentblock {}
        }
        oo::objdefine {
          if {[llength $thisline]==3} {
            lassign $thisline tcmd name body
            my keyword.Class info $commentblock $name $body
          } else {
            puts "Warning: bare oo::define in library"
          }
        }
        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"
................................................................................
          set commentblock {}
        }
        oo::class {
          lassign $thisline tcmd mthd name body
          my keyword.class info $commentblock $name $body
          set commentblock {}
        }
        default {
          if {[lindex [split $cmd ::] end] eq "define"} {
            lassign $thisline tcmd name body
            my keyword.class info $commentblock $name $body
            set commentblock {}
          }
          set commentblock {}
        }
      }
      set thisline {}
    }
  }

  method section.command {procinfo} {
    set 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 " \[opt \""
          } else {
            append line " "
          }
          if {$positional} {
            append line "\[arg $argname"
          } else {
            append line "\[option $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 " \[const \"[dict get $arginfo default]\"\]"
            }
            append line "\"\]"
          }
        }
      }
      append line \]
      putb result $line
      if {[dict exists $minfo description]} {
        putb result [dict get $minfo description]
      }
    }
    putb result {[list_end]}
    return $result
  }

  method section.class {class_name class_info} {
    set result {}
    putb result "\[subsection \{Class  $class_name\}\]"
    if {[dict exists $class_info ancestors]} {
      set line "\[emph \"ancestors\"\]:"
      foreach {c} [dict get $class_info ancestors] {
        append line " \[class [string trim $c :]\]"
      }
      putb result $line
      putb result {[para]}
    }
    dict for {f v} $class_info {
      if {$f in {class_method method description ancestors}} continue
      putb result "\[emph \"$f\"\]: $v"
      putb result {[para]}
    }
    if {[dict exists $class_info description]} {
      putb result [dict get $class_info description]
      putb result {[para]}
    }
    if {[dict exists $class_info class_method]} {
      putb result "\[class \{Class Methods\}\]"
      #putb result "Methods on the class object itself."
      putb result {[list_begin definitions]}
      dict for {method minfo} [dict get $class_info class_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 " \[opt \""
            } else {
              append line " "
            }
            if {$positional} {
              append line "\[arg $argname"
            } else {
              append line "\[option $argname"
              if {[dict exists $arginfo type]} {
                append line " \[method [dict get $arginfo type]\]"
              } else {
                append line " \[method $argname\]"
              }
            }
            append line "\]"
            if {$mandatory==0} {
              if {[dict exists $arginfo default]} {
                append line " \[const \"[dict get $arginfo default]\"\]"
              }
              append line "\"\]"
            }
          }
        }
        append line \]
        putb result $line
        if {[dict exists $minfo description]} {
          putb result [dict get $minfo description]
        }
      }
      putb result {[list_end]}
      putb result {[para]}
    }
    if {[dict exists $class_info method]} {
      putb result "\[class {Methods}\]"
      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 " \[opt \""
            } else {
              append line " "
            }
            if {$positional} {
              append line "\[arg $argname"
            } else {
              append line "\[opt $argname"
              if {[dict exists $arginfo type]} {
                append line " \[method [dict get $arginfo type]\]"
              } else {
                append line " \[method $argname\]"
              }
            }
            append line "\]"
            if {$mandatory==0} {
              if {[dict exists $arginfo default]} {
                append line " \[const \"[dict get $arginfo default]\"\]"
              }
              append line "\"\]"
            }
          }
        }
        append line \]
        putb result $line
        if {[dict exists $minfo description]} {
          putb result [dict get $minfo description]
        }
      }
      putb result {[list_end]}


      putb result {[para]}
    }
    return $result
  }

  method manpage args {
    my variable info map
    set result {}
................................................................................
    putb result $header
    dict for {sec_type sec_info} $info {
      switch $sec_type {
        proc {
          putb result [my section.command $sec_info]
        }
        class {
          putb result "\[section Classes\]"
          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 description]} {
            putb result [dict get $sec_info description]
          }
        }
      }
    }
    putb result $footer
    putb result {[manpage_end]}
    return $result

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

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
     HTTP_HOST [my request get HTTP_HOST] \
     SESSION [my request get SESSION] \
    ]
  }

  ###
  # Accept the handoff from the server object of the socket
  # [enph newsock] and feed it the state [emph datastate]
  #
  # Fields the [emph datastate] are looking for in particular are:
  #

  # mixin: A key/value list of slots and classes to be mixed into the
  # object prior to invoking [cmd Dispatch].
  #

  # http: A key/value list of values to populate the object's [emph request]
  # ensemble
  #

  # All other fields are passed along to the [emph clay] structure of the object.
  ###
  method dispatch {newsock datastate} {
    my variable chan request
    try {
      set chan $newsock
      chan event $chan readable {}
      chan configure $chan -translation {auto crlf} -buffering line







|
<

<
>
|

<
>
|

<
>
|







282
283
284
285
286
287
288
289

290

291
292
293

294
295
296

297
298
299
300
301
302
303
304
305
     HTTP_HOST [my request get HTTP_HOST] \
     SESSION [my request get SESSION] \
    ]
  }

  ###
  # Accept the handoff from the server object of the socket
  # [emph newsock] and feed it the state [emph datastate].

  # Fields the [emph datastate] are looking for in particular are:

  # [para]
  # * [const mixin] - A key/value list of slots and classes to be mixed into the
  # object prior to invoking [cmd Dispatch].

  # [para]
  # * [const http] - A key/value list of values to populate the object's [emph request]
  # ensemble

  # [para]
  # All other fields are passed along to the [method clay] structure of the object.
  ###
  method dispatch {newsock datastate} {
    my variable chan request
    try {
      set chan $newsock
      chan event $chan readable {}
      chan configure $chan -translation {auto crlf} -buffering line

Changes to modules/httpd/httpd.man.

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
my puts </BODY></HTML>
  }
}
::docserver::server create HTTPD port 8015 myaddr 127.0.0.1
HTTPD add_uri /* [list mixin reply.hello]
}]


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



[list_begin definitions]

[call method [cmd ChannelCopy] [arg in] [arg out] ?[arg args]?]


[call method [cmd html_header] ?[arg title] [emph ""]? ?[arg args]?]


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


[call method [cmd http_code_string] [arg code]]


[call method [cmd HttpHeaders] [arg sock] ?[arg debug] [emph ""]?]


[call method [cmd HttpHeaders_Default]]


[call method [cmd HttpServerHeaders]]


[call method [cmd MimeParse] [arg mimetext]]

 Converts a block of mime encoded text to a key/value list. If an exception is encountered,
 the method will generate its own call to the [cmd error] method, and immediately invoke
 the [cmd output] method to produce an error code and close the connection.




[call method [cmd Url_Decode] [arg data]]
 De-httpizes a string.



[call method [cmd Url_PathCheck] [arg urlsuffix]]


[call method [cmd wait] [arg mode] [arg sock]]

[list_end]
 Author: Sean Woods, yoda@etoyoc.com


 Adapted from the "minihttpd.tcl" file distributed with Tclhttpd




 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]?]


[call method [cmd destructor] ?[arg dictargs]?]

 clean up on exit




[call method [cmd close]]

 Close channels opened by this object




[call method [cmd Log_Dispatched]]

 Record a dispatch event




[call method [cmd dispatch] [arg newsock] [arg datastate]]

 Accept the handoff from the server object of the socket
 [enph newsock] and feed it the state [emph datastate]

 Fields the [emph datastate] are looking for in particular are:


 mixin: A key/value list of slots and classes to be mixed into the
 object prior to invoking [cmd Dispatch].


 http: A key/value list of values to populate the object's [emph request]
 ensemble



 All other fields are passed along to the [emph clay] structure of the object.



[call method [cmd Dispatch]]


[call method [cmd html_css]]


[call method [cmd html_header] [arg title] ?[arg args]?]


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


[call method [cmd error] [arg code] ?[arg msg] [emph ""]? ?[arg errorInfo] [emph ""]?]


[call method [cmd content]]

 REPLACE ME:
 This method is the "meat" of your application.
 It writes to the result buffer via the "puts" method
 and can tweak the headers via "clay put header_reply"




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

 Formulate a standard HTTP status header from he string provided.




[call method [cmd log] [arg type] ?[arg info] [emph ""]?]


[call method [cmd CoroName]]


[call method [cmd DoOutput]]

 Generates the the HTTP reply, streams that reply back across [arg chan],
 and destroys the object.




[call method [cmd FormData]]

 For GET requests, converts the QUERY_DATA header into a key/value list.

 For POST requests, reads the Post data and converts that information to
 a key/value list for application/x-www-form-urlencoded posts. For multipart
 posts, it composites all of the MIME headers of the post to a singular key/value
 list, and provides MIME_* information as computed by the [cmd mime] package, including
 the MIME_TOKEN, which can be fed back into the mime package to read out the contents.




[call method [cmd PostData] [arg length]]
 Stream [arg length] bytes from the [arg chan] socket, but only of the request is a
 POST or PUSH. Returns an empty string otherwise.



[call method [cmd Session_Load]]
 Manage session data



[call method [cmd TransferComplete] ?[arg args]?]
 Intended to be invoked from [cmd {chan copy}] as a callback. This closes every channel
 fed to it on the command line, and then destroys the object.

 [example {
     ###
     # Output the body
     ###
     chan configure $sock -translation binary -blocking 0 -buffering full -buffersize 4096
     chan configure $chan -translation binary -blocking 0 -buffering full -buffersize 4096
     if {$length} {
       ###
       # Send any POST/PUT/etc content
       ###
       chan copy $sock $chan -size $SIZE -command [info coroutine]
       yield
     }
     catch {close $sock}
     chan flush $chan
 }]



[call method [cmd puts] [arg line]]
 Appends the value of [arg string] to the end of [arg reply_body], as well as a trailing newline
 character.



[call method [cmd RequestFind] [arg field]]


[call method [cmd request] [arg subcommand] ?[arg args]?]


[call method [cmd reply] [arg subcommand] ?[arg args]?]


[call method [cmd reset]]
 Clear the contents of the [arg reply_body] variable, and reset all headers in the [cmd reply]
 structure back to the defaults for this object.



[call method [cmd timeOutCheck]]
 Called from the [cmd http::server] object which spawned this reply. Checks to see
 if too much time has elapsed while waiting for data or generating a reply, and issues
 a timeout error to the request if it has, as well as destroy the object and close the
 [arg chan] socket.



[call method [cmd timestamp]]

 Return the current system time in the format: [example {%a, %d %b %Y %T %Z}]


[list_end]

 A class which shephards a request through the process of generating a
 reply.

 The socket associated with the reply is available at all times as the [arg chan]
 variable.

 The process of generating a reply begins with an [cmd httpd::server] generating a
 [cmd http::class] object, mixing in a set of behaviors and then invoking the reply
 object's [cmd dispatch] method.

 In normal operations the [cmd dispatch] method:

 [list_begin enumerated]

 [enum]
 Invokes the [cmd reset] method for the object to populate default headers.

 [enum]
 Invokes the [cmd HttpHeaders] method to stream the MIME headers out of the socket

 [enum]
 Invokes the [cmd {request parse}] method to convert the stream of MIME headers into a
 dict that can be read via the [cmd request] method.

 [enum]
 Stores the raw stream of MIME headers in the [arg rawrequest] variable of the object.

 [enum]
 Invokes the [cmd content] method for the object, generating an call to the [cmd error]
 method if an exception is raised.

 [enum]
 Invokes the [cmd output] method for the object
 [list_end]




 [para]

 [section {Reply Method Ensembles}]

 The [cmd http::reply] class and its derivatives maintain several variables as dictionaries
 internally. Access to these dictionaries is managed through a dedicated ensemble. The
 ensemble implements most of the same behaviors as the [cmd dict] command.

 Each ensemble implements the following methods above, beyond, or modifying standard dicts:

 [list_begin definitions]

 [call method [cmd ENSEMBLE::add] [arg field] [arg element]]

 Add [arg element] to a list stored in [arg field], but only if it is not already present om the list.

 [call method [cmd ENSEMBLE::dump]]

 Return the current contents of the data structure as a key/value list.

 [call method [cmd ENSEMBLE::get] [arg field]]

 Return the value of the field [arg field], or an empty string if it does not exist.

 [call method [cmd ENSEMBLE::reset]]

 Return a key/value list of the default contents for this data structure.

 [call method [cmd ENSEMBLE::remove] [arg field] [arg element]]

 Remove all instances of [arg element] from the list stored in [arg field].

 [call method [cmd ENSEMBLE::replace] [arg keyvaluelist]]

 Replace the internal dict with the contents of [arg keyvaluelist]

 [call method [cmd ENSEMBLE::reset]]

 Replace the internal dict with the default state.

 [call method [cmd ENSEMBLE::set] [arg field] [arg value]]

 Set the value of [arg field] to [arg value].

 [list_end]

 [section {Reply Method Ensemble: http_info}]

 Manages HTTP headers passed in by the server.

 Ensemble Methods:

 [list_begin definitions]

 [call method [cmd http_info::netstring]]

 Return the contents of this data structure as a netstring encoded block.

 [list_end]

 [section {Reply Method Ensemble: request}]

 Managed data from MIME headers of the request.

 [list_begin definitions]

 [call method  [cmd request::parse] [arg string]]

 Replace the contents of the data structure with information encoded in a MIME
 formatted block of text ([arg string]).

 [list_end]

 [section {Reply Method Ensemble: reply}]

 Manage the headers sent in the reply.


 [list_begin definitions]

 [call method [cmd reply::output]]

 Return the contents of this data structure as a MIME encoded block appropriate
 for an HTTP response.

 [list_end]


 [section {Reply Methods}]

 [list_begin definitions]
 [call method [cmd close]]

 Terminate the transaction, and close the socket.


 [call method [cmd HttpHeaders] [arg sock] [arg ?debug?]]

 Stream MIME headers from the socket [arg sock], stopping at an empty line. Returns
 the stream as a block of text.

 [call method [cmd dispatch] [arg newsock] [arg datastate]]

 Take over control of the socket [arg newsock], and store that as the [arg chan] variable
 for the object. This method runs through all of the steps of reading HTTP headers, generating
 content, and closing the connection. (See class writetup).

 [call method [cmd error] [arg code] [arg ?message?] [arg ?errorInfo?]]

 Generate an error message of the specified [arg code], and display the [arg message] as the
 reason for the exception. [arg errorInfo] is passed in from calls, but how or if it should be
 displayed is a prerogative of the developer.

 [call method [cmd content]]

 Generate the content for the reply. This method is intended to be replaced by the mixin.

 Developers have the option of streaming output to a buffer via the [cmd puts] method of the
 reply, or simply populating the [arg reply_body] variable of the object.
 The information returned by the [cmd content] method is not interpreted in any way.

 If an exception is thrown (via the [cmd error] command in Tcl, for example) the caller will
 auto-generate a 500 {Internal Error} message.

 A typical implementation of [cmd content] look like:

 [example {

 clay::define ::test::content.file {
 	superclass ::httpd::content.file
 	# Return a file
 	# Note: this is using the content.file mixin which looks for the reply_file variable
 	# and will auto-compute the Content-Type
 	method content {} {
 	  my reset
     set doc_root [my request get DOCUMENT_ROOT]
     my variable reply_file
     set reply_file [file join $doc_root index.html]
 	}
 }
 clay::define ::test::content.time {
   # return the current system time
 	method content {} {
 		my variable reply_body
     my reply set Content-Type text/plain
 		set reply_body [clock seconds]
 	}
 }
 clay::define ::test::content.echo {
 	method content {} {
 		my variable reply_body
     my reply set Content-Type [my request get CONTENT_TYPE]
 		set reply_body [my PostData [my request get CONTENT_LENGTH]]
 	}
 }
 clay::define ::test::content.form_handler {
 	method content {} {
 	  set form [my FormData]
 	  my reply set Content-Type {text/html; charset=UTF-8}
     my puts [my html_header {My Dynamic Page}]
     my puts "<BODY>"
     my puts "You Sent<p>"
     my puts "<TABLE>"
     foreach {f v} $form {
       my puts "<TR><TH>$f</TH><TD><verbatim>$v</verbatim></TD>"
     }
     my puts "</TABLE><p>"
     my puts "Send some info:<p>"
     my puts "<FORM action=/[my request get REQUEST_PATH] method POST>"
     my puts "<TABLE>"
     foreach field {name rank serial_number} {
       set line "<TR><TH>$field</TH><TD><input name=\"$field\" "
       if {[dict exists $form $field]} {
         append line " value=\"[dict get $form $field]\"""
       }
       append line " /></TD></TR>"
       my puts $line
     }
     my puts "</TABLE>"
     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"]?]


[call method [cmd destructor] ?[arg dictargs]?]


[call method [cmd connect] [arg sock] [arg ip] [arg port]]

 Reply to an open socket. This method builds a coroutine to manage the remainder
 of the connection. The coroutine's operations are driven by the [cmd Connect] method.




[call method [cmd ServerHeaders] [arg ip] [arg http_request] [arg mimetxt]]


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

 This method reads HTTP headers, and then consults the [cmd dispatch] method to
 determine if the request is valid, and/or what kind of reply to generate. Under
 normal cases, an object of class [cmd ::http::reply] is created, and that class's
 [cmd dispatch] method.
 This action passes control of the socket to
 the reply object. The reply object manages the rest of the transaction, including
 closing the socket.




[call method [cmd counter] [arg which]]
 Increment an internal counter.



[call method [cmd CheckTimeout]]

 Check open connections for a time out event.




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


[call method [cmd dispatch] [arg data]]

 Given a key/value list of information, return a data structure describing how
 the server should reply.




[call method [cmd Dispatch_Default] [arg reply]]

 Method dispatch method of last resort before returning a 404 NOT FOUND error.
 The default behavior is to look for a file in [emph DOCUMENT_ROOT] which
 matches the query.




[call method [cmd Dispatch_Local] [arg data]]

 Method dispatch method invoked prior to invoking methods implemented by plugins.
 If this method returns a non-empty dictionary, that structure will be passed to
 the reply. The default is an empty implementation.




[call method [cmd Headers_Local] [arg varname]]

 Introspect and possibly modify a data structure destined for a reply. This
 method is invoked before invoking Header methods implemented by plugins.
 The default implementation is empty.




[call method [cmd Headers_Process] [arg varname]]

 Introspect and possibly modify a data structure destined for a reply. This
 method is built dynamically by the [cmd plugin] method.




[call method [cmd HostName] [arg ipaddr]]

 Convert an ip address to a host name. If the server/ reverse_dns flag
 is false, this method simply returns the IP address back.
 Internally, this method uses the [emph dns] module from tcllib.




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

 Log an event. The input for args is free form. This method is intended
 to be replaced by the user, and is a noop for a stock http::server object.




[call method [cmd plugin] [arg slot] ?[arg class] [emph ""]?]

 Incorporate behaviors from a plugin.
 This method dynamically rebuilds the [cmd Dispatch] and [cmd Headers]
 method. For every plugin, the server looks for the following entries in
 [emph "clay plugin/"]:
 [para]
 [emph load] - A script to invoke in the server's namespace during the [cmd plugin] method invokation.
 [para]
 [emph dispatch] - A script to stitch into the server's [cmd Dispatch] method.
 [para]
 [emph headers] - A script to stitch into the server's [cmd Headers] method.
 [para]
 [emph thread] - A script to stitch into the server's [cmd Thread_start] method.




[call method [cmd port_listening]]
 Return the actual port that httpd is listening on.



[call method [cmd PrefixNormalize] [arg prefix]]
 For the stock version, trim trailing /'s and *'s from a prefix. This
 method can be replaced by the end user to perform any other transformations
 needed for the application.



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


[call method [cmd start]]
 Open the socket listener.



[call method [cmd stop]]
 Shut off the socket listener, and destroy any pending replies.



[call method [cmd SubObject::db]]


[call method [cmd SubObject::default]]


[call method [cmd template] [arg page]]
 Return a template for the string [arg page]



[call method [cmd TemplateSearch] [arg page]]
 Perform a search for the template that best matches [arg page]. This
 can include local file searches, in-memory structures, or even
 database lookups. The stock implementation simply looks for files
 with a .tml or .html extension in the [opt doc_root] directory.



[call method [cmd Thread_start]]

 Built by the [cmd plugin] method. Called by the [cmd start] method. Intended
 to allow plugins to spawn worker threads.




[call method [cmd Uuid_Generate]]

 Generate a GUUID. Used to ensure every request has a unique ID.
 The default implementation is:
 [example {
   return [::uuid::uuid generate]
 }]




[call method [cmd Validate_Connection] [arg sock] [arg ip]]

 Given a socket and an ip address, return true if this connection should
 be terminated, or false if it should be allowed to continue. The stock
 implementation always returns 0. This is intended for applications to
 be able to implement black lists and/or provide security based on IP
 address.


[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]]


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

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

[call method [cmd content]]


[call method [cmd Dispatch]]

[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 proxy_path]]


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


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


[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 proxy_channel]]


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


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


[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 proxy_channel]]


[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]]

 Implementation of the dispatcher




[call method [cmd uri::add] [arg vhosts] [arg patterns] [arg info]]





[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]?]


[call method [cmd Connect_Local] [arg uuid] [arg sock] ?[arg args]?]

 A modified connection method that passes simple GET request to an object
 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]








>
|
>
>
>


|


|


|





|










|
|
|
>




|


>






<
>

<
>
>
>

<
<
<
|
|

>
>

>
>
>

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


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


|

|



>


|
>





|
>





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

<









|


|


|




|
|
|
|
>





|



>
|







|
|
>





|

|
|
|
|
|
>




|
|


>

|


>
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


>

|
|


>



|


|



|
|
>



|
|
|
|


>


|


<

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

>
>
|

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

<
>

<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|




|
|
>








|
|
|
|
|
|
|
>




|
>




|



>
|




|
|
>





|
|
|
>





|
|
|
>





|
|
|
>





|
|



>


|
|
|



>
|

|
|



>
|

|
|
|
|
|
|
|
|
|
|
|
|



>

|
>



|
|
|
>






|
>



|
>









|
>



|
|
|
|
>




|
|
>





|
|
|
|
|



>


|
|
|
|
|


<

|
>

<
<
<
<
<
|
>
>

|



>
>
|
>
>
>








>

>

<
>
>





>

>

<
>
>





>

>

<
>
>
>
>
>
>
>
>







 







>

<
|
<

<
<
<
>
>








>

>
>
>

<
>
>
>
>
>
>











|





>

<
>
>
>

<
<
<
>
>











|




|
>



>

>

<
>
>
>
>
>
>





>

<
>
>
>

<
<
<
>
>











|


>

>
>
>

<
>
>
>
>
>
>


|





>

<
>

>


>
>
>
|

<
>



>
>
|

<
>
>



<
>
>




|
>







>




>

<
|
>
>

<
<
|
>











>

>

<
>
>


|


|

|
|

|
|
>



|









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
my puts </BODY></HTML>
  }
}
::docserver::server create HTTPD port 8015 myaddr 127.0.0.1
HTTPD add_uri /* [list mixin reply.hello]
}]

[section Classes]
[subsection {Class  httpd::mime}]

[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd ChannelCopy] [arg in] [arg out] [opt "[arg args]"]]


[call method [cmd html_header] [opt "[arg title] [const ""]"] [opt "[arg args]"]]


[call method [cmd html_footer] [opt "[arg args]"]]


[call method [cmd http_code_string] [arg code]]


[call method [cmd HttpHeaders] [arg sock] [opt "[arg debug] [const ""]"]]


[call method [cmd HttpHeaders_Default]]


[call method [cmd HttpServerHeaders]]


[call method [cmd MimeParse] [arg mimetext]]

Converts a block of mime encoded text to a key/value list. If an exception is encountered,
the method will generate its own call to the [cmd error] method, and immediately invoke
the [cmd output] method to produce an error code and close the connection.




[call method [cmd Url_Decode] [arg data]]
De-httpizes a string.



[call method [cmd Url_PathCheck] [arg urlsuffix]]


[call method [cmd wait] [arg mode] [arg sock]]

[list_end]

[para]


[subsection {Class  httpd::reply}]
[emph "ancestors"]: [class httpd::mime]
[para]




A class which shephards a request through the process of generating a
reply.

The socket associated with the reply is available at all times as the [arg chan]
variable.

The process of generating a reply begins with an [cmd httpd::server] generating a
[cmd http::class] object, mixing in a set of behaviors and then invoking the reply
object's [cmd dispatch] method.


In normal operations the [cmd dispatch] method:

[list_begin enumerated]

[enum]
Invokes the [cmd reset] method for the object to populate default headers.

[enum]
Invokes the [cmd HttpHeaders] method to stream the MIME headers out of the socket

[enum]
Invokes the [cmd {request parse}] method to convert the stream of MIME headers into a
dict that can be read via the [cmd request] method.

[enum]
Stores the raw stream of MIME headers in the [arg rawrequest] variable of the object.

[enum]
Invokes the [cmd content] method for the object, generating an call to the [cmd error]
method if an exception is raised.

[enum]
Invokes the [cmd output] method for the object
[list_end]

[para]

[section {Reply Method Ensembles}]

The [cmd http::reply] class and its derivatives maintain several variables as dictionaries
internally. Access to these dictionaries is managed through a dedicated ensemble. The
ensemble implements most of the same behaviors as the [cmd dict] command.

Each ensemble implements the following methods above, beyond, or modifying standard dicts:

[list_begin definitions]

[call method [cmd ENSEMBLE::add] [arg field] [arg element]]

Add [arg element] to a list stored in [arg field], but only if it is not already present om the list.

[call method [cmd ENSEMBLE::dump]]

Return the current contents of the data structure as a key/value list.

[call method [cmd ENSEMBLE::get] [arg field]]

Return the value of the field [arg field], or an empty string if it does not exist.

[call method [cmd ENSEMBLE::reset]]

Return a key/value list of the default contents for this data structure.

[call method [cmd ENSEMBLE::remove] [arg field] [arg element]]

Remove all instances of [arg element] from the list stored in [arg field].

[call method [cmd ENSEMBLE::replace] [arg keyvaluelist]]

Replace the internal dict with the contents of [arg keyvaluelist]

[call method [cmd ENSEMBLE::reset]]

Replace the internal dict with the default state.

[call method [cmd ENSEMBLE::set] [arg field] [arg value]]

Set the value of [arg field] to [arg value].

[list_end]

[section {Reply Method Ensemble: http_info}]

Manages HTTP headers passed in by the server.

Ensemble Methods:

[list_begin definitions]

[call method [cmd http_info::netstring]]

Return the contents of this data structure as a netstring encoded block.

[list_end]

[section {Reply Method Ensemble: request}]

Managed data from MIME headers of the request.

[list_begin definitions]

[call method  [cmd request::parse] [arg string]]

Replace the contents of the data structure with information encoded in a MIME
formatted block of text ([arg string]).

[list_end]

[section {Reply Method Ensemble: reply}]

Manage the headers sent in the reply.


[list_begin definitions]

[call method [cmd reply::output]]

Return the contents of this data structure as a MIME encoded block appropriate
for an HTTP response.

[list_end]

[section {Reply Methods}]

[list_begin definitions]
[call method [cmd close]]

Terminate the transaction, and close the socket.

[call method [cmd HttpHeaders] [arg sock] [arg ?debug?]]

Stream MIME headers from the socket [arg sock], stopping at an empty line. Returns
the stream as a block of text.

[call method [cmd dispatch] [arg newsock] [arg datastate]]

Take over control of the socket [arg newsock], and store that as the [arg chan] variable
for the object. This method runs through all of the steps of reading HTTP headers, generating
content, and closing the connection. (See class writetup).

[call method [cmd error] [arg code] [arg ?message?] [arg ?errorInfo?]]

Generate an error message of the specified [arg code], and display the [arg message] as the
reason for the exception. [arg errorInfo] is passed in from calls, but how or if it should be
displayed is a prerogative of the developer.

[call method [cmd content]]

Generate the content for the reply. This method is intended to be replaced by the mixin.

Developers have the option of streaming output to a buffer via the [cmd puts] method of the
reply, or simply populating the [arg reply_body] variable of the object.
The information returned by the [cmd content] method is not interpreted in any way.

If an exception is thrown (via the [cmd error] command in Tcl, for example) the caller will
auto-generate a 500 {Internal Error} message.

A typical implementation of [cmd content] look like:

[example {

clay::define ::test::content.file {
superclass ::httpd::content.file
# Return a file
# Note: this is using the content.file mixin which looks for the reply_file variable
# and will auto-compute the Content-Type
method content {} {
my reset
set doc_root [my request get DOCUMENT_ROOT]
my variable reply_file
set reply_file [file join $doc_root index.html]
}
}
clay::define ::test::content.time {
# return the current system time
method content {} {
my variable reply_body
my reply set Content-Type text/plain
set reply_body [clock seconds]
}
}
clay::define ::test::content.echo {
method content {} {
my variable reply_body
my reply set Content-Type [my request get CONTENT_TYPE]
set reply_body [my PostData [my request get CONTENT_LENGTH]]
}
}
clay::define ::test::content.form_handler {
method content {} {
set form [my FormData]
my reply set Content-Type {text/html; charset=UTF-8}
my puts [my html_header {My Dynamic Page}]
my puts "<BODY>"
my puts "You Sent<p>"
my puts "<TABLE>"
foreach {f v} $form {
my puts "<TR><TH>$f</TH><TD><verbatim>$v</verbatim></TD>"
}
my puts "</TABLE><p>"
my puts "Send some info:<p>"
my puts "<FORM action=/[my request get REQUEST_PATH] method POST>"
my puts "<TABLE>"
foreach field {name rank serial_number} {
set line "<TR><TH>$field</TH><TD><input name=\"$field\" "
if {[dict exists $form $field]} {
append line " value=\"[dict get $form $field]\"""
}
append line " /></TD></TR>"
my puts $line
}
my puts "</TABLE>"
my puts [my html footer]
}
}

}]
[list_end]



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd constructor] [arg ServerObj] [opt "[arg args]"]]


[call method [cmd destructor] [opt "[arg dictargs]"]]

clean up on exit




[call method [cmd close]]

Close channels opened by this object




[call method [cmd Log_Dispatched]]

Record a dispatch event




[call method [cmd dispatch] [arg newsock] [arg datastate]]

Accept the handoff from the server object of the socket
[emph newsock] and feed it the state [emph datastate].

Fields the [emph datastate] are looking for in particular are:

[para]
* [const mixin] - A key/value list of slots and classes to be mixed into the
object prior to invoking [cmd Dispatch].

[para]
* [const http] - A key/value list of values to populate the object's [emph request]
ensemble
[para]
All other fields are passed along to the [method clay] structure of the object.





[call method [cmd Dispatch]]


[call method [cmd html_css]]


[call method [cmd html_header] [arg title] [opt "[arg args]"]]


[call method [cmd html_footer] [opt "[arg args]"]]


[call method [cmd error] [arg code] [opt "[arg msg] [const ""]"] [opt "[arg errorInfo] [const ""]"]]


[call method [cmd content]]

REPLACE ME:
This method is the "meat" of your application.
It writes to the result buffer via the "puts" method
and can tweak the headers via "clay put header_reply"




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

Formulate a standard HTTP status header from he string provided.




[call method [cmd log] [arg type] [opt "[arg info] [const ""]"]]


[call method [cmd CoroName]]


[call method [cmd DoOutput]]

Generates the the HTTP reply, streams that reply back across [arg chan],
and destroys the object.




[call method [cmd FormData]]

For GET requests, converts the QUERY_DATA header into a key/value list.

For POST requests, reads the Post data and converts that information to
a key/value list for application/x-www-form-urlencoded posts. For multipart
posts, it composites all of the MIME headers of the post to a singular key/value
list, and provides MIME_* information as computed by the [cmd mime] package, including
the MIME_TOKEN, which can be fed back into the mime package to read out the contents.




[call method [cmd PostData] [arg length]]
Stream [arg length] bytes from the [arg chan] socket, but only of the request is a
POST or PUSH. Returns an empty string otherwise.



[call method [cmd Session_Load]]
Manage session data



[call method [cmd TransferComplete] [opt "[arg args]"]]
Intended to be invoked from [cmd {chan copy}] as a callback. This closes every channel
fed to it on the command line, and then destroys the object.

[example {
###
# Output the body
###
chan configure $sock -translation binary -blocking 0 -buffering full -buffersize 4096
chan configure $chan -translation binary -blocking 0 -buffering full -buffersize 4096
if {$length} {
###
# Send any POST/PUT/etc content
###
chan copy $sock $chan -size $SIZE -command [info coroutine]
yield
}
catch {close $sock}
chan flush $chan
}]



[call method [cmd puts] [arg line]]
Appends the value of [arg string] to the end of [arg reply_body], as well as a trailing newline
character.



[call method [cmd RequestFind] [arg field]]


[call method [cmd request] [arg subcommand] [opt "[arg args]"]]


[call method [cmd reply] [arg subcommand] [opt "[arg args]"]]


[call method [cmd reset]]
Clear the contents of the [arg reply_body] variable, and reset all headers in the [cmd reply]
structure back to the defaults for this object.



[call method [cmd timeOutCheck]]
Called from the [cmd http::server] object which spawned this reply. Checks to see
if too much time has elapsed while waiting for data or generating a reply, and issues
a timeout error to the request if it has, as well as destroy the object and close the
[arg chan] socket.



[call method [cmd timestamp]]

Return the current system time in the format: [example {%a, %d %b %Y %T %Z}]





































[list_end]
[para]

[subsection {Class  httpd::server}]
[emph "ancestors"]: [class httpd::mime]
[para]






















































































[para]
[class {Methods}]

[list_begin definitions]



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



































































































[call method [cmd destructor] [opt "[arg dictargs]"]]


[call method [cmd connect] [arg sock] [arg ip] [arg port]]

Reply to an open socket. This method builds a coroutine to manage the remainder
of the connection. The coroutine's operations are driven by the [cmd Connect] method.




[call method [cmd ServerHeaders] [arg ip] [arg http_request] [arg mimetxt]]


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

This method reads HTTP headers, and then consults the [cmd dispatch] method to
determine if the request is valid, and/or what kind of reply to generate. Under
normal cases, an object of class [cmd ::http::reply] is created, and that class's
[cmd dispatch] method.
This action passes control of the socket to
the reply object. The reply object manages the rest of the transaction, including
closing the socket.




[call method [cmd counter] [arg which]]
Increment an internal counter.



[call method [cmd CheckTimeout]]

Check open connections for a time out event.




[call method [cmd debug] [opt "[arg args]"]]


[call method [cmd dispatch] [arg data]]

Given a key/value list of information, return a data structure describing how
the server should reply.




[call method [cmd Dispatch_Default] [arg reply]]

Method dispatch method of last resort before returning a 404 NOT FOUND error.
The default behavior is to look for a file in [emph DOCUMENT_ROOT] which
matches the query.




[call method [cmd Dispatch_Local] [arg data]]

Method dispatch method invoked prior to invoking methods implemented by plugins.
If this method returns a non-empty dictionary, that structure will be passed to
the reply. The default is an empty implementation.




[call method [cmd Headers_Local] [arg varname]]

Introspect and possibly modify a data structure destined for a reply. This
method is invoked before invoking Header methods implemented by plugins.
The default implementation is empty.




[call method [cmd Headers_Process] [arg varname]]

Introspect and possibly modify a data structure destined for a reply. This
method is built dynamically by the [cmd plugin] method.




[call method [cmd HostName] [arg ipaddr]]

Convert an ip address to a host name. If the server/ reverse_dns flag
is false, this method simply returns the IP address back.
Internally, this method uses the [emph dns] module from tcllib.




[call method [cmd log] [opt "[arg args]"]]

Log an event. The input for args is free form. This method is intended
to be replaced by the user, and is a noop for a stock http::server object.




[call method [cmd plugin] [arg slot] [opt "[arg class] [const ""]"]]

Incorporate behaviors from a plugin.
This method dynamically rebuilds the [cmd Dispatch] and [cmd Headers]
method. For every plugin, the server looks for the following entries in
[emph "clay plugin/"]:
[para]
[emph load] - A script to invoke in the server's namespace during the [cmd plugin] method invokation.
[para]
[emph dispatch] - A script to stitch into the server's [cmd Dispatch] method.
[para]
[emph headers] - A script to stitch into the server's [cmd Headers] method.
[para]
[emph thread] - A script to stitch into the server's [cmd Thread_start] method.




[call method [cmd port_listening]]
Return the actual port that httpd is listening on.



[call method [cmd PrefixNormalize] [arg prefix]]
For the stock version, trim trailing /'s and *'s from a prefix. This
method can be replaced by the end user to perform any other transformations
needed for the application.



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


[call method [cmd start]]
Open the socket listener.



[call method [cmd stop]]
Shut off the socket listener, and destroy any pending replies.



[call method [cmd SubObject::db]]


[call method [cmd SubObject::default]]


[call method [cmd template] [arg page]]
Return a template for the string [arg page]



[call method [cmd TemplateSearch] [arg page]]
Perform a search for the template that best matches [arg page]. This
can include local file searches, in-memory structures, or even
database lookups. The stock implementation simply looks for files
with a .tml or .html extension in the [opt doc_root] directory.



[call method [cmd Thread_start]]

Built by the [cmd plugin] method. Called by the [cmd start] method. Intended
to allow plugins to spawn worker threads.




[call method [cmd Uuid_Generate]]

Generate a GUUID. Used to ensure every request has a unique ID.
The default implementation is:
[example {
return [::uuid::uuid generate]
}]




[call method [cmd Validate_Connection] [arg sock] [arg ip]]

Given a socket and an ip address, return true if this connection should
be terminated, or false if it should be allowed to continue. The stock
implementation always returns 0. This is intended for applications to
be able to implement black lists and/or provide security based on IP
address.




[list_end]
[para]






[subsection {Class  httpd::server::dispatch}]
[emph "ancestors"]: [class httpd::server]
[para]

Provide a backward compadible alias



[para]

[subsection {Class  httpd::content.redirect}]

[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd reset]]


[call method [cmd content]]

[list_end]
[para]

[subsection {Class  httpd::content.cache}]


[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd Dispatch]]

[list_end]
[para]

[subsection {Class  httpd::content.template}]


[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd content]]

[list_end]
[para]

[subsection {Class  httpd::content.file}]


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



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd FileName]]


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

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

[call method [cmd content]]


[call method [cmd Dispatch]]

[list_end]
[para]


[subsection {Class  httpd::content.exec}]





[para]
[class {Methods}]
[list_begin definitions]

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


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

[list_end]
[para]

[subsection {Class  httpd::content.proxy}]
[emph "ancestors"]: [class httpd::content.exec]
[para]


Return data from an proxy process



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd proxy_channel]]


[call method [cmd proxy_path]]


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


[call method [cmd ProxyReply] [arg chana] [arg chanb] [opt "[arg args]"]]


[call method [cmd Dispatch]]

[list_end]
[para]


[subsection {Class  httpd::content.cgi}]
[emph "ancestors"]: [class httpd::content.proxy]
[para]




[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd FileName]]


[call method [cmd proxy_channel]]


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


[call method [cmd ProxyReply] [arg chana] [arg chanb] [opt "[arg args]"]]


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

For most CGI applications a directory list is vorboten



[list_end]
[para]

[subsection {Class  httpd::protocol.scgi}]


Return data from an SCGI process



[para]
[class {Methods}]
[list_begin definitions]

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

[list_end]
[para]


[subsection {Class  httpd::content.scgi}]
[emph "ancestors"]: [class httpd::content.proxy]
[para]




[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd scgi_info]]


[call method [cmd proxy_channel]]


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


[call method [cmd ProxyReply] [arg chana] [arg chanb] [opt "[arg args]"]]

[list_end]
[para]

[subsection {Class  httpd::server.scgi}]
[emph "ancestors"]: [class httpd::server]
[para]


Act as an  SCGI Server



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd debug] [opt "[arg args]"]]


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

[list_end]
[para]


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

Upgrade a connection to a websocket



[para]

[subsection {Class  httpd::plugin}]


httpd plugin template



[para]

[subsection {Class  httpd::plugin.dict_dispatch}]


A rudimentary plugin that dispatches URLs from a dict
data structure




[para]
[class {Methods}]
[list_begin definitions]

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

Implementation of the dispatcher




[call method [cmd uri::add] [arg vhosts] [arg patterns] [arg info]]





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

[list_end]
[para]


[subsection {Class  httpd::reply.memchan}]
[emph "ancestors"]: [class httpd::reply]
[para]



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd output]]


[call method [cmd DoOutput]]


[call method [cmd close]]

[list_end]
[para]

[subsection {Class  httpd::plugin.local_memchan}]


[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd local_memchan] [arg command] [opt "[arg args]"]]


[call method [cmd Connect_Local] [arg uuid] [arg sock] [opt "[arg args]"]]

A modified connection method that passes simple GET request to an object
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]
[para]

[section AUTHORS]
Sean Woods

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

[manpage_end]

Changes to modules/httpd/httpd.tcl.

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
     HTTP_HOST [my request get HTTP_HOST] \
     SESSION [my request get SESSION] \
    ]
  }

  ###
  # Accept the handoff from the server object of the socket
  # [enph newsock] and feed it the state [emph datastate]
  #
  # Fields the [emph datastate] are looking for in particular are:
  #

  # mixin: A key/value list of slots and classes to be mixed into the
  # object prior to invoking [cmd Dispatch].
  #

  # http: A key/value list of values to populate the object's [emph request]
  # ensemble
  #

  # All other fields are passed along to the [emph clay] structure of the object.
  ###
  method dispatch {newsock datastate} {
    my variable chan request
    try {
      set chan $newsock
      chan event $chan readable {}
      chan configure $chan -translation {auto crlf} -buffering line







|
<

<
>
|

<
>
|

<
>
|







607
608
609
610
611
612
613
614

615

616
617
618

619
620
621

622
623
624
625
626
627
628
629
630
     HTTP_HOST [my request get HTTP_HOST] \
     SESSION [my request get SESSION] \
    ]
  }

  ###
  # Accept the handoff from the server object of the socket
  # [emph newsock] and feed it the state [emph datastate].

  # Fields the [emph datastate] are looking for in particular are:

  # [para]
  # * [const mixin] - A key/value list of slots and classes to be mixed into the
  # object prior to invoking [cmd Dispatch].

  # [para]
  # * [const http] - A key/value list of values to populate the object's [emph request]
  # ensemble

  # [para]
  # All other fields are passed along to the [method clay] structure of the object.
  ###
  method dispatch {newsock datastate} {
    my variable chan request
    try {
      set chan $newsock
      chan event $chan readable {}
      chan configure $chan -translation {auto crlf} -buffering line

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

1
2
3








4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
97
98
99
100
101
102
103















104
105
106
107
108
109
110
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
###
# 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
###
if {[info command ::noop] eq {}} {
  proc ::noop args {}
}

proc ::practcl::debug args {
  #puts $args
  ::practcl::cputs ::DEBUG_INFO $args
}

###
................................................................................
  return $result
}

proc ::practcl::os {} {
  return [${::practcl::MAIN} define get TEACUP_OS]
}
















if {[::package vcompare $::tcl_version 8.6] < 0} {
  # Approximate ::zipfile::mkzip with exec calls
  proc ::practcl::mkzip {exename barekit vfspath} {
    set path [file dirname [file normalize $exename]]
    set zipfile [file join $path [file rootname $exename].zip]
    file copy -force $barekit $exename
    set pwd [pwd]
................................................................................
  proc ::practcl::sort_dict list {
    set result {}
    foreach key [lsort -dictionary [dict keys $list]] {
      dict set result $key [dict get $list $key]
    }
    return $result
  }
} else {
  proc ::practcl::mkzip {exename barekit vfspath} {
    ::practcl::tcllib_require zipfile::mkzip
    ::zipfile::mkzip::mkzip $exename -runtime $barekit -directory $vfspath
  }
  proc ::practcl::sort_dict list {
    return [::lsort -stride 2 -dictionary $list]
  }
}

proc ::practcl::local_os {} {
  # If we have already run this command, return
  # a cached copy of the data
  if {[info exists ::practcl::LOCAL_INFO]} {
    return $::practcl::LOCAL_INFO
  }



>
>
>
>
>
>
>
>








<
|
<







 







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







 







<
<
<
<
|
<
<
|
|







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
...
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
...
144
145
146
147
148
149
150




151


152
153
154
155
156
157
158
159
160
###
# Build utility functions
###

###
# Generate a proc if no command already exists by that name
###
proc Proc {name arglist body} {
  if {[info command $name] ne {}} return
  proc $name $arglist $body
}

###
# 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
###

Proc ::noop args {}


proc ::practcl::debug args {
  #puts $args
  ::practcl::cputs ::DEBUG_INFO $args
}

###
................................................................................
  return $result
}

proc ::practcl::os {} {
  return [${::practcl::MAIN} define get TEACUP_OS]
}

###
# Build a zipfile. On tcl8.6 this invokes the native Zip implementation
# on older interpreters this invokes zip via exec
###
proc ::practcl::mkzip {exename barekit vfspath} {
  ::practcl::tcllib_require zipfile::mkzip
  ::zipfile::mkzip::mkzip $exename -runtime $barekit -directory $vfspath
}
###
# Dictionary sort a key/value list. Needed because pre tcl8.6
# does not have [emph {lsort -stride 2}]
###
proc ::practcl::sort_dict list {
  return [::lsort -stride 2 -dictionary $list]
}
if {[::package vcompare $::tcl_version 8.6] < 0} {
  # Approximate ::zipfile::mkzip with exec calls
  proc ::practcl::mkzip {exename barekit vfspath} {
    set path [file dirname [file normalize $exename]]
    set zipfile [file join $path [file rootname $exename].zip]
    file copy -force $barekit $exename
    set pwd [pwd]
................................................................................
  proc ::practcl::sort_dict list {
    set result {}
    foreach key [lsort -dictionary [dict keys $list]] {
      dict set result $key [dict get $list $key]
    }
    return $result
  }




}





proc ::practcl::local_os {} {
  # If we have already run this command, return
  # a cached copy of the data
  if {[info exists ::practcl::LOCAL_INFO]} {
    return $::practcl::LOCAL_INFO
  }

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




1
2
3
4
5
6
7



::oo::class create ::practcl::object {
  superclass ::practcl::metaclass

  constructor {parent args} {
    my variable links define
    set organs [$parent child organs]
    my clay delegate {*}$organs
>
>
>







1
2
3
4
5
6
7
8
9
10
###
# A generic Practcl object
###
::oo::class create ::practcl::object {
  superclass ::practcl::metaclass

  constructor {parent args} {
    my variable links define
    set organs [$parent child organs]
    my clay delegate {*}$organs

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

1
2
3

4
5
6
7
8
9
10

::oo::class create ::practcl::product {



  method code {section body} {
    my variable code
    ::practcl::cputs code($section) $body
  }

  method Collate_Source CWD {}
|
|
|
>







1
2
3
4
5
6
7
8
9
10
11
###
# A deliverable for the build system
###
::clay::define ::practcl::product {

  method code {section body} {
    my variable code
    ::practcl::cputs code($section) $body
  }

  method Collate_Source CWD {}

Changes to modules/practcl/practcl.man.

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
...
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
...
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
...
526
527
528
529
530
531
532
533
534

535
536
537
538
539
540
541

542
543
544
545
546
547
548
...
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
...
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
...
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
...
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
...
899
900
901
902
903
904
905
906
907

908
909
910
911
912
913
914
...
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
....
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
....
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
[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 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 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-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-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 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 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 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-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 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 go]]


[call method [cmd linktype]]

[list_end]


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

[manpage_end]








|
<
<

>

<


<

>

|
|
|
|
|



>
>
>
>
|

|



>
|


|


|


|


|







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






|
>






|
<
<
<
|
|
>








|

|
>





<
<


<
|
<
<





|
|
>





|
|



>
|
|
|
|
|
>





|







|



>
|













|
>





|
|
|
>






|

|
|
>






|


|

<
<

<
<
|


|



>
|
>
>
>
>
>





|


|





|








|











>

>

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




|
>













|
|
|
|
|
|



>
|





|
|
|
|
|
|
|
|












|
>







 







|
>





|
>



>

>
>
>

<
>
>



|
>



|
>












|
>





>

>
>
>

<
>
>


|







 







>

>
>
>

<
>
>
>
>
>
>


|








>

>

<
>
>
>
>
>
>
>
>


|

|
>






|


|








|


|


|
|
>





|


|
|
>







|
>








|
>







 







|
|
>





|
|
>







|
|
|

>

>

<
<
|
>
>



|
>
>
>
>
>
>
>
>











|







|
>







 







|
|
>





|
|
>







 







|







|
|
>







 







|
>





|



>
|


>

>
>
>

<
>
>
>
>
>
>








>

<
>
>
>

<
<
<
>
>





>

>
>
>

<
>
>





>

>
>
>

<
>
>





>

>
>
>

>
>
|
>
>

>
>
>

<
>
>
>
>





|


|


|

|
>








|
|
>





|
|
>







 







>

<
|
|
>

<
<
>
|





|





|


|











|
|
>








|


>

>
>
>

<
>
>







 







|
>





|
|
|


>
|


|


>

>
>
>

<
>
>








|
|
>



>

>

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







 







>

<
|
|
>

>
>
>

>

<
>
>
>
>
>
>





>

>
>
>

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






|
>











>

>
>
>

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











>

>
>
>

<
>
>







 







|
|
>







 







|
|
|


|
>





|
>





|
>





|
|
>





|
>












>

>
>
>

<
>
>
>
>
>
>
>











>

<
<
<
>
>
|
|


<
>
|







 







|

>
>
>

<
>
>


|





>

>
>
>

<
>
>





>

>
>
>

<
>
>







 







|


>

>
>
>

<
>
>
>
>
>
>







 







>

<
>
>
>

>

<
|
>
>

<
<
>
>





>

>
>
>
>

<
>
>
>





|

>
>
>

<
>
>







 







|






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
...
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
...
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
...
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
...
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
...
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
...
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
....
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
....
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
....
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203

1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223



1224
1225
1226
1227
1228
1229

1230
1231
1232
1233
1234
1235
1236
1237
1238
....
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251

1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267

1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280

1281
1282
1283
1284
1285
1286
1287
1288
1289
....
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305

1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
....
1340
1341
1342
1343
1344
1345
1346
1347
1348

1349
1350
1351
1352
1353
1354

1355
1356
1357
1358


1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372

1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386

1387
1388
1389
1390
1391
1392
1393
1394
1395
....
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
[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 Proc] [arg name] [arg arglist] [arg body]]



Generate a proc if no command already exists by that name






[call proc [cmd noop] [opt "[arg args]"]]

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::debug] [opt "[arg args]"]]


[call proc [cmd practcl::doexec] [opt "[arg args]"]]

Drop in a static copy of Tcl




[call proc [cmd practcl::doexec_in] [arg path] [opt "[arg args]"]]


[call proc [cmd practcl::dotclexec] [opt "[arg args]"]]


[call proc [cmd practcl::domake] [arg path] [opt "[arg args]"]]


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


[call proc [cmd practcl::fossil] [arg path] [opt "[arg args]"]]


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


[call proc [cmd practcl::os]]


[call proc [cmd practcl::mkzip] [arg exename] [arg barekit] [arg vfspath]]

Build a zipfile. On tcl8.6 this invokes the native Zip implementation
on older interpreters this invokes zip via exec




[call proc [cmd practcl::sort_dict] [arg list]]

Dictionary sort a key/value list. Needed because pre tcl8.6
does not have [emph {lsort -stride 2}]




[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] [opt "[arg args]"]]



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] [opt "[arg localdat] [const ""]"]]

Read a stylized key/value list stored in a file




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






[call proc [cmd practcl::read_sh_file] [arg filename] [opt "[arg localdat] [const ""]"]]





[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] [opt "[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] [opt "[arg style] [const "tcl"]"] [opt "[arg note] [const ""]"]]


[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] [opt "[arg files] [const ""]"]]


[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] [opt "[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] [opt "[arg toplevel] [const "1"]"]]


[call proc [cmd practcl::trigger] [opt "[arg args]"]]






[call proc [cmd practcl::depends] [opt "[arg args]"]]


[call proc [cmd practcl::target] [arg name] [arg info] [opt "[arg action] [const ""]"]]

[list_end]

[section Classes]
[subsection {Class  practcl::metaclass}]
[emph "ancestors"]: [class oo::object]
[para]

[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd _MorphPatterns]]


[call method [cmd define] [arg submethod] [opt "[arg args]"]]


[call method [cmd graft] [opt "[arg args]"]]


[call method [cmd initialize]]


[call method [cmd link] [arg command] [opt "[arg args]"]]


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


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


[call method [cmd organ] [opt "[arg args]"]]


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


[call method [cmd select]]


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

[list_end]
[para]

[subsection {Class  practcl::toolset}]


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



[para]
[class {Class Methods}]
[list_begin definitions]

[call method [cmd select] [arg object]]

[list_end]
[para]
[class {Methods}]
[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] [opt "[arg args]"]]


[call method [cmd make-autodetect]]

[list_end]
[para]

[subsection {Class  practcl::toolset.gcc}]
[emph "ancestors"]: [class practcl::toolset]
[para]

[para]
[class {Methods}]
[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 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]
[para]

[subsection {Class  practcl::toolset.msvc}]
[emph "ancestors"]: [class practcl::toolset]
[para]


[para]
[class {Methods}]
[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]
[para]

[subsection {Class  practcl::make_obj}]
[emph "ancestors"]: [class practcl::metaclass]
[para]


[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd constructor] [arg module_object] [arg name] [arg info] [opt "[arg action_body] [const ""]"]]


[call method [cmd do]]


[call method [cmd check]]

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

[call method [cmd reset]]


[call method [cmd triggers]]

[list_end]
[para]

[subsection {Class  practcl::object}]
[emph "ancestors"]: [class practcl::metaclass]
[para]


A generic Practcl object



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd constructor] [arg parent] [opt "[arg args]"]]


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


[call method [cmd go]]

[list_end]
[para]

[subsection {Class  practcl::dynamic}]


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



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd cstructure] [arg name] [arg definition] [opt "[arg argdat] [const ""]"]]

Parser functions




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


[call method [cmd include_dir] [opt "[arg args]"]]


[call method [cmd include_directory] [opt "[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] [opt "[arg info] [const ""]"]]


[call method [cmd c_tcloomethod] [arg name] [arg body] [opt "[arg arginfo] [const ""]"]]


[call method [cmd cmethod] [arg name] [arg body] [opt "[arg arginfo] [const ""]"]]
Alias to classic name



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


[call method [cmd c_tclcmd] [arg name] [arg body] [opt "[arg arginfo] [const ""]"]]


[call method [cmd c_tclproc_raw] [arg name] [arg body] [opt "[arg arginfo] [const ""]"]]
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]
[para]



[subsection {Class  practcl::product}]

A deliverable for the build system



[para]
[class {Class Methods}]
[list_begin definitions]

[call method [cmd select] [arg object]]

[list_end]
[para]
[class {Methods}]
[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] [opt "[arg spaces] [const ""]"]]


[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-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-loader-module]]


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


[call method [cmd IncludeAdd] [arg headervar] [opt "[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] [opt "[arg args]"]]

[list_end]
[para]

[subsection {Class  practcl::product.cheader}]
[emph "ancestors"]: [class practcl::product]
[para]


Flesh out several trivial varieties of product



[para]
[class {Methods}]
[list_begin definitions]

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


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

[list_end]
[para]


[subsection {Class  practcl::product.csource}]
[emph "ancestors"]: [class practcl::product]
[para]




[para]
[class {Methods}]
[list_begin definitions]

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

[list_end]
[para]

[subsection {Class  practcl::product.clibrary}]
[emph "ancestors"]: [class practcl::product]
[para]


[para]
[class {Methods}]
[list_begin definitions]

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

[list_end]
[para]

[subsection {Class  practcl::product.dynamic}]
[emph "ancestors"]: [class practcl::dynamic] [class practcl::product]
[para]


[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd initialize]]

[list_end]
[para]

[subsection {Class  practcl::product.critcl}]
[emph "ancestors"]: [class practcl::dynamic] [class practcl::product]
[para]

[para]

[subsection {Class  practcl::module}]
[emph "ancestors"]: [class practcl::object] [class practcl::product.dynamic]
[para]

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




[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd _MorphPatterns]]


[call method [cmd add] [opt "[arg args]"]]


[call method [cmd install-headers] [opt "[arg args]"]]


[call method [cmd make] [arg command] [opt "[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]
[para]


[subsection {Class  practcl::project}]
[emph "ancestors"]: [class practcl::module]
[para]



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd _MorphPatterns]]


[call method [cmd constructor] [opt "[arg args]"]]


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


[call method [cmd add_project] [arg pkg] [arg info] [opt "[arg oodefine] [const ""]"]]


[call method [cmd add_tool] [arg pkg] [arg info] [opt "[arg oodefine] [const ""]"]]


[call method [cmd build-tclcore]]


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


[call method [cmd linktype]]


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



[call method [cmd tclcore]]


[call method [cmd tkcore]]


[call method [cmd tool] [arg pkg] [opt "[arg args]"]]

[list_end]
[para]

[subsection {Class  practcl::library}]
[emph "ancestors"]: [class practcl::project]
[para]


[para]
[class {Methods}]
[list_begin definitions]

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


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

................................................................................
[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] [opt "[arg args]"]]
Create a "package ifneeded"
Args are a list of aliases for which this package will answer to



[call method [cmd shared_library] [opt "[arg filename] [const ""]"]]


[call method [cmd static_library] [opt "[arg filename] [const ""]"]]

[list_end]
[para]

[subsection {Class  practcl::tclkit}]
[emph "ancestors"]: [class practcl::library]
[para]


[para]
[class {Methods}]
[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] [opt "[arg args]"]]
Wrap an executable



[list_end]
[para]

[subsection {Class  practcl::distribution}]


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



[para]
[class {Class Methods}]
[list_begin definitions]

[call method [cmd Sandbox] [arg object]]


[call method [cmd select] [arg object]]


[call method [cmd claim_path] [arg path]]


[call method [cmd claim_object] [arg object]]

[list_end]
[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd scm_info]]


[call method [cmd DistroMixIn]]

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

[call method [cmd ScmUpdate]]


[call method [cmd Unpack]]

[list_end]
[para]


[subsection {Class  practcl::distribution.snapshot}]
[emph "ancestors"]: [class practcl::distribution]
[para]

[para]
[class {Class Methods}]
[list_begin definitions]

[call method [cmd claim_path] [arg path]]



[call method [cmd claim_object] [arg object]]

[list_end]
[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd ScmUnpack]]

[list_end]
[para]

[subsection {Class  practcl::distribution.fossil}]
[emph "ancestors"]: [class practcl::distribution]
[para]


[para]
[class {Class Methods}]
[list_begin definitions]

[call method [cmd claim_path] [arg path]]
Check for markers in the source root



[call method [cmd claim_object] [arg obj]]
Check for markers in the metadata


[list_end]
[para]
[class {Methods}]
[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]
[para]

[subsection {Class  practcl::distribution.git}]
[emph "ancestors"]: [class practcl::distribution]
[para]


[para]
[class {Class Methods}]
[list_begin definitions]

[call method [cmd claim_path] [arg path]]


[call method [cmd claim_object] [arg obj]]

[list_end]
[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd ScmTag]]


[call method [cmd ScmUnpack]]


[call method [cmd ScmUpdate]]

[list_end]
[para]

[subsection {Class  practcl::subproject}]
[emph "ancestors"]: [class practcl::module]
[para]


[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd _MorphPatterns]]


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

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

[call method [cmd compile]]


[call method [cmd go]]


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



[call method [cmd linktype]]


[call method [cmd linker-products] [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]
[para]

[subsection {Class  practcl::subproject.source}]
[emph "ancestors"]: [class practcl::subproject] [class practcl::library]
[para]


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



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd env-bootstrap]]


[call method [cmd env-present]]


[call method [cmd linktype]]

[list_end]
[para]




[subsection {Class  practcl::subproject.teapot}]
[emph "ancestors"]: [class practcl::subproject]
[para]
a copy from the teapot



[para]
[class {Methods}]
[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]
[para]

[subsection {Class  practcl::subproject.kettle}]
[emph "ancestors"]: [class practcl::subproject]
[para]


[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd kettle] [arg path] [opt "[arg args]"]]


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

[list_end]
[para]

[subsection {Class  practcl::subproject.critcl}]
[emph "ancestors"]: [class practcl::subproject]
[para]


[para]
[class {Methods}]
[list_begin definitions]

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

[list_end]
[para]

[subsection {Class  practcl::subproject.sak}]
[emph "ancestors"]: [class practcl::subproject]
[para]


[para]
[class {Methods}]
[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] [opt "[arg args]"]]

[list_end]
[para]

[subsection {Class  practcl::subproject.binary}]
[emph "ancestors"]: [class practcl::subproject]
[para]


A binary package



[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd clean]]


[call method [cmd env-install]]

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

[call method [cmd Configure]]


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

[list_end]
[para]


[subsection {Class  practcl::subproject.tea}]
[emph "ancestors"]: [class practcl::subproject.binary]
[para]

[para]


[subsection {Class  practcl::subproject.library}]
[emph "ancestors"]: [class practcl::subproject.binary] [class practcl::library]
[para]



[para]
[class {Methods}]
[list_begin definitions]

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

[list_end]
[para]

[subsection {Class  practcl::subproject.external}]
[emph "ancestors"]: [class practcl::subproject.binary]
[para]
An external library



[para]
[class {Methods}]
[list_begin definitions]

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

[list_end]
[para]

[subsection {Class  practcl::subproject.core}]
[emph "ancestors"]: [class practcl::subproject.binary]
[para]


[para]
[class {Methods}]
[list_begin definitions]

[call method [cmd env-bootstrap]]


[call method [cmd env-present]]

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

[call method [cmd go]]


[call method [cmd linktype]]

[list_end]
[para]

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

[manpage_end]

Changes to modules/practcl/practcl.tcl.

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
....
1030
1031
1032
1033
1034
1035
1036















1037
1038
1039
1040
1041
1042
1043
....
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
....
3453
3454
3455
3456
3457
3458
3459



3460
3461
3462
3463
3464
3465
3466
....
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114

4115
4116
4117
4118
4119
4120
4121
###
###
# START: buildutil.tcl
###
###
# 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
###
if {[info command ::noop] eq {}} {
  proc ::noop args {}
}

proc ::practcl::debug args {
  #puts $args
  ::practcl::cputs ::DEBUG_INFO $args
}

###
................................................................................
  return $result
}

proc ::practcl::os {} {
  return [${::practcl::MAIN} define get TEACUP_OS]
}
















if {[::package vcompare $::tcl_version 8.6] < 0} {
  # Approximate ::zipfile::mkzip with exec calls
  proc ::practcl::mkzip {exename barekit vfspath} {
    set path [file dirname [file normalize $exename]]
    set zipfile [file join $path [file rootname $exename].zip]
    file copy -force $barekit $exename
    set pwd [pwd]
................................................................................
  proc ::practcl::sort_dict list {
    set result {}
    foreach key [lsort -dictionary [dict keys $list]] {
      dict set result $key [dict get $list $key]
    }
    return $result
  }
} else {
  proc ::practcl::mkzip {exename barekit vfspath} {
    ::practcl::tcllib_require zipfile::mkzip
    ::zipfile::mkzip::mkzip $exename -runtime $barekit -directory $vfspath
  }
  proc ::practcl::sort_dict list {
    return [::lsort -stride 2 -dictionary $list]
  }
}

proc ::practcl::local_os {} {
  # If we have already run this command, return
  # a cached copy of the data
  if {[info exists ::practcl::LOCAL_INFO]} {
    return $::practcl::LOCAL_INFO
  }
................................................................................

###
# END: class target.tcl
###
###
# START: class object.tcl
###



::oo::class create ::practcl::object {
  superclass ::practcl::metaclass

  constructor {parent args} {
    my variable links define
    set organs [$parent child organs]
    my clay delegate {*}$organs
................................................................................

###
# END: class dynamic.tcl
###
###
# START: class product.tcl
###

::oo::class create ::practcl::product {



  method code {section body} {
    my variable code
    ::practcl::cputs code($section) $body
  }

  method Collate_Source CWD {}







>
>
>
>
>
>
>
>








<
|
<







 







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







 







<
<
<
<
|
<
<
|
|







 







>
>
>







 







|
|
|
>







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
....
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
....
1077
1078
1079
1080
1081
1082
1083




1084


1085
1086
1087
1088
1089
1090
1091
1092
1093
....
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
....
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
###
###
# START: buildutil.tcl
###
###
# Build utility functions
###

###
# Generate a proc if no command already exists by that name
###
proc Proc {name arglist body} {
  if {[info command $name] ne {}} return
  proc $name $arglist $body
}

###
# 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
###

Proc ::noop args {}


proc ::practcl::debug args {
  #puts $args
  ::practcl::cputs ::DEBUG_INFO $args
}

###
................................................................................
  return $result
}

proc ::practcl::os {} {
  return [${::practcl::MAIN} define get TEACUP_OS]
}

###
# Build a zipfile. On tcl8.6 this invokes the native Zip implementation
# on older interpreters this invokes zip via exec
###
proc ::practcl::mkzip {exename barekit vfspath} {
  ::practcl::tcllib_require zipfile::mkzip
  ::zipfile::mkzip::mkzip $exename -runtime $barekit -directory $vfspath
}
###
# Dictionary sort a key/value list. Needed because pre tcl8.6
# does not have [emph {lsort -stride 2}]
###
proc ::practcl::sort_dict list {
  return [::lsort -stride 2 -dictionary $list]
}
if {[::package vcompare $::tcl_version 8.6] < 0} {
  # Approximate ::zipfile::mkzip with exec calls
  proc ::practcl::mkzip {exename barekit vfspath} {
    set path [file dirname [file normalize $exename]]
    set zipfile [file join $path [file rootname $exename].zip]
    file copy -force $barekit $exename
    set pwd [pwd]
................................................................................
  proc ::practcl::sort_dict list {
    set result {}
    foreach key [lsort -dictionary [dict keys $list]] {
      dict set result $key [dict get $list $key]
    }
    return $result
  }




}





proc ::practcl::local_os {} {
  # If we have already run this command, return
  # a cached copy of the data
  if {[info exists ::practcl::LOCAL_INFO]} {
    return $::practcl::LOCAL_INFO
  }
................................................................................

###
# END: class target.tcl
###
###
# START: class object.tcl
###
###
# A generic Practcl object
###
::oo::class create ::practcl::object {
  superclass ::practcl::metaclass

  constructor {parent args} {
    my variable links define
    set organs [$parent child organs]
    my clay delegate {*}$organs
................................................................................

###
# END: class dynamic.tcl
###
###
# START: class product.tcl
###
###
# A deliverable for the build system
###
::clay::define ::practcl::product {

  method code {section body} {
    my variable code
    ::practcl::cputs code($section) $body
  }

  method Collate_Source CWD {}