Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch ldap-60160205fe-tls Excluding Merge-Ins
This is equivalent to a diff from 7538200f88 to 2d8a920b69
2018-12-08
| ||
15:53 | Re-integrating kbk's disjoint-set work check-in: c261a6a0ea user: hypnotoad tags: trunk | |
2018-09-24
| ||
18:37 | ldap/ldapx <EF,T> Tkt [60160205fe] completed & merged check-in: 5e2cff31b4 user: andreask tags: pooryorick | |
18:36 | ldap/ldapx <T> Tkt [60160205fe] Added test Closed-Leaf check-in: 2d8a920b69 user: andreask tags: ldap-60160205fe-tls | |
18:13 | Update the ldap branch to latest. check-in: db19a51e4c user: andreask tags: ldap-60160205fe-tls | |
2018-08-14
| ||
19:16 | Fix issue [a16b1095974e071d], error in mime.tcl check-in: 074ec6a961 user: pooryorick tags: pooryorick | |
2018-07-22
| ||
11:38 | Add a package for trigonometric functions that use angles in degrees and additional trigonometric and hyperbolic functions, including their inverses. check-in: 7538200f88 user: arjenmarkus tags: trunk | |
2018-07-19
| ||
19:31 | Change the criterium for detecting if two circles touch - use the mean of the two radii check-in: 6124e077a8 user: arjenmarkus tags: trunk | |
Changes to embedded/www/index.html.
︙ | ︙ | |||
2341 2342 2343 2344 2345 2346 2347 | <td class="#doctools_idxleft" width="35%"><a name="matching"> matching </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/grammar_me/me_intro.html"> grammar::me_intro </a> · <a href="tcllib/files/modules/grammar_peg/peg_interp.html"> grammar::peg::interp </a> · <a href="tcllib/files/apps/pt.html"> pt </a> · <a href="tcllib/files/modules/pt/pt_astree.html"> pt::ast </a> · <a href="tcllib/files/modules/pt/pt_cparam_config_critcl.html"> pt::cparam::configuration::critcl </a> · <a href="tcllib/files/modules/pt/pt_cparam_config_tea.html"> pt::cparam::configuration::tea </a> · <a href="tcllib/files/modules/pt/pt_json_language.html"> pt::json_language </a> · <a href="tcllib/files/modules/pt/pt_param.html"> pt::param </a> · <a href="tcllib/files/modules/pt/pt_pexpression.html"> pt::pe </a> · <a href="tcllib/files/modules/pt/pt_pexpr_op.html"> pt::pe::op </a> · <a href="tcllib/files/modules/pt/pt_pegrammar.html"> pt::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_container.html"> pt::peg::container </a> · <a href="tcllib/files/modules/pt/pt_peg_container_peg.html"> pt::peg::container::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_export.html"> pt::peg::export </a> · <a href="tcllib/files/modules/pt/pt_peg_export_container.html"> pt::peg::export::container </a> · <a href="tcllib/files/modules/pt/pt_peg_export_json.html"> pt::peg::export::json </a> · <a href="tcllib/files/modules/pt/pt_peg_export_peg.html"> pt::peg::export::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_from_container.html"> pt::peg::from::container </a> · <a href="tcllib/files/modules/pt/pt_peg_from_json.html"> pt::peg::from::json </a> · <a href="tcllib/files/modules/pt/pt_peg_from_peg.html"> pt::peg::from::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_import.html"> pt::peg::import </a> · <a href="tcllib/files/modules/pt/pt_peg_import_container.html"> pt::peg::import::container </a> · <a href="tcllib/files/modules/pt/pt_peg_import_json.html"> pt::peg::import::json </a> · <a href="tcllib/files/modules/pt/pt_peg_import_peg.html"> pt::peg::import::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_interp.html"> pt::peg::interp </a> · <a href="tcllib/files/modules/pt/pt_peg_to_container.html"> pt::peg::to::container </a> · <a href="tcllib/files/modules/pt/pt_peg_to_cparam.html"> pt::peg::to::cparam </a> · <a href="tcllib/files/modules/pt/pt_peg_to_json.html"> pt::peg::to::json </a> · <a href="tcllib/files/modules/pt/pt_peg_to_param.html"> pt::peg::to::param </a> · <a href="tcllib/files/modules/pt/pt_peg_to_peg.html"> pt::peg::to::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_to_tclparam.html"> pt::peg::to::tclparam </a> · <a href="tcllib/files/modules/pt/pt_peg_language.html"> pt::peg_language </a> · <a href="tcllib/files/modules/pt/pt_peg_introduction.html"> pt::pegrammar </a> · <a href="tcllib/files/modules/pt/pt_pgen.html"> pt::pgen </a> · <a href="tcllib/files/modules/pt/pt_rdengine.html"> pt::rde </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_nx.html"> pt::tclparam::configuration::nx </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_snit.html"> pt::tclparam::configuration::snit </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_tcloo.html"> pt::tclparam::configuration::tcloo </a> · <a href="tcllib/files/modules/pt/pt_util.html"> pt::util </a> · <a href="tcllib/files/modules/pt/pt_to_api.html"> pt_export_api </a> · <a href="tcllib/files/modules/pt/pt_from_api.html"> pt_import_api </a> · <a href="tcllib/files/modules/pt/pt_introduction.html"> pt_introduction </a> · <a href="tcllib/files/modules/pt/pt_parse_peg.html"> pt_parse_peg </a> · <a href="tcllib/files/modules/pt/pt_parser_api.html"> pt_parser_api </a> · <a href="tcllib/files/modules/pt/pt_peg_op.html"> pt_peg_op </a> · <a href="tcllib/files/modules/struct/graphops.html"> struct::graph::op </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="math"> math </a></td> <td class="#doctools_idxright" width="65%"> | | | 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 | <td class="#doctools_idxleft" width="35%"><a name="matching"> matching </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/grammar_me/me_intro.html"> grammar::me_intro </a> · <a href="tcllib/files/modules/grammar_peg/peg_interp.html"> grammar::peg::interp </a> · <a href="tcllib/files/apps/pt.html"> pt </a> · <a href="tcllib/files/modules/pt/pt_astree.html"> pt::ast </a> · <a href="tcllib/files/modules/pt/pt_cparam_config_critcl.html"> pt::cparam::configuration::critcl </a> · <a href="tcllib/files/modules/pt/pt_cparam_config_tea.html"> pt::cparam::configuration::tea </a> · <a href="tcllib/files/modules/pt/pt_json_language.html"> pt::json_language </a> · <a href="tcllib/files/modules/pt/pt_param.html"> pt::param </a> · <a href="tcllib/files/modules/pt/pt_pexpression.html"> pt::pe </a> · <a href="tcllib/files/modules/pt/pt_pexpr_op.html"> pt::pe::op </a> · <a href="tcllib/files/modules/pt/pt_pegrammar.html"> pt::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_container.html"> pt::peg::container </a> · <a href="tcllib/files/modules/pt/pt_peg_container_peg.html"> pt::peg::container::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_export.html"> pt::peg::export </a> · <a href="tcllib/files/modules/pt/pt_peg_export_container.html"> pt::peg::export::container </a> · <a href="tcllib/files/modules/pt/pt_peg_export_json.html"> pt::peg::export::json </a> · <a href="tcllib/files/modules/pt/pt_peg_export_peg.html"> pt::peg::export::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_from_container.html"> pt::peg::from::container </a> · <a href="tcllib/files/modules/pt/pt_peg_from_json.html"> pt::peg::from::json </a> · <a href="tcllib/files/modules/pt/pt_peg_from_peg.html"> pt::peg::from::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_import.html"> pt::peg::import </a> · <a href="tcllib/files/modules/pt/pt_peg_import_container.html"> pt::peg::import::container </a> · <a href="tcllib/files/modules/pt/pt_peg_import_json.html"> pt::peg::import::json </a> · <a href="tcllib/files/modules/pt/pt_peg_import_peg.html"> pt::peg::import::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_interp.html"> pt::peg::interp </a> · <a href="tcllib/files/modules/pt/pt_peg_to_container.html"> pt::peg::to::container </a> · <a href="tcllib/files/modules/pt/pt_peg_to_cparam.html"> pt::peg::to::cparam </a> · <a href="tcllib/files/modules/pt/pt_peg_to_json.html"> pt::peg::to::json </a> · <a href="tcllib/files/modules/pt/pt_peg_to_param.html"> pt::peg::to::param </a> · <a href="tcllib/files/modules/pt/pt_peg_to_peg.html"> pt::peg::to::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_to_tclparam.html"> pt::peg::to::tclparam </a> · <a href="tcllib/files/modules/pt/pt_peg_language.html"> pt::peg_language </a> · <a href="tcllib/files/modules/pt/pt_peg_introduction.html"> pt::pegrammar </a> · <a href="tcllib/files/modules/pt/pt_pgen.html"> pt::pgen </a> · <a href="tcllib/files/modules/pt/pt_rdengine.html"> pt::rde </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_nx.html"> pt::tclparam::configuration::nx </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_snit.html"> pt::tclparam::configuration::snit </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_tcloo.html"> pt::tclparam::configuration::tcloo </a> · <a href="tcllib/files/modules/pt/pt_util.html"> pt::util </a> · <a href="tcllib/files/modules/pt/pt_to_api.html"> pt_export_api </a> · <a href="tcllib/files/modules/pt/pt_from_api.html"> pt_import_api </a> · <a href="tcllib/files/modules/pt/pt_introduction.html"> pt_introduction </a> · <a href="tcllib/files/modules/pt/pt_parse_peg.html"> pt_parse_peg </a> · <a href="tcllib/files/modules/pt/pt_parser_api.html"> pt_parser_api </a> · <a href="tcllib/files/modules/pt/pt_peg_op.html"> pt_peg_op </a> · <a href="tcllib/files/modules/struct/graphops.html"> struct::graph::op </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="math"> math </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/math/math.html"> math </a> · <a href="tcllib/files/modules/math/bigfloat.html"> math::bigfloat </a> · <a href="tcllib/files/modules/math/bignum.html"> math::bignum </a> · <a href="tcllib/files/modules/math/calculus.html"> math::calculus </a> · <a href="tcllib/files/modules/math/qcomplex.html"> math::complexnumbers </a> · <a href="tcllib/files/modules/math/constants.html"> math::constants </a> · <a href="tcllib/files/modules/math/decimal.html"> math::decimal </a> · <a href="tcllib/files/modules/math/fuzzy.html"> math::fuzzy </a> · <a href="tcllib/files/modules/math/math_geometry.html"> math::geometry </a> · <a href="tcllib/files/modules/math/interpolate.html"> math::interpolate </a> · <a href="tcllib/files/modules/math/linalg.html"> math::linearalgebra </a> · <a href="tcllib/files/modules/math/optimize.html"> math::optimize </a> · <a href="tcllib/files/modules/math/pca.html"> math::PCA </a> · <a href="tcllib/files/modules/math/polynomials.html"> math::polynomials </a> · <a href="tcllib/files/modules/math/rational_funcs.html"> math::rationalfunctions </a> · <a href="tcllib/files/modules/math/special.html"> math::special </a> · <a href="tcllib/files/modules/math/trig.html"> math::trig </a> · <a href="tcllib/files/modules/simulation/annealing.html"> simulation::annealing </a> · <a href="tcllib/files/modules/simulation/montecarlo.html"> simulation::montecarlo </a> · <a href="tcllib/files/modules/simulation/simulation_random.html"> simulation::random </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="mathematics"> mathematics </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/math/fourier.html"> math::fourier </a> · <a href="tcllib/files/modules/math/statistics.html"> math::statistics </a> </td></tr> <tr class="#doctools_idxeven" valign=top> |
︙ | ︙ | |||
4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 | </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="treeql"> TreeQL </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/treeql/treeql.html"> treeql </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="trimming"> trimming </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/textutil/textutil.html"> textutil </a> · <a href="tcllib/files/modules/textutil/trim.html"> textutil::trim </a> </td></tr> | > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 | </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="treeql"> TreeQL </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/treeql/treeql.html"> treeql </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="trigonometry"> trigonometry </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/math/trig.html"> math::trig </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="trimming"> trimming </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/textutil/textutil.html"> textutil </a> · <a href="tcllib/files/modules/textutil/trim.html"> textutil::trim </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="twitter"> twitter </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/oauth/oauth.html"> oauth </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="type"> type </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/fileutil/fileutil.html"> fileutil </a> · <a href="tcllib/files/modules/fumagic/cfront.html"> fileutil::magic::cfront </a> · <a href="tcllib/files/modules/fumagic/cgen.html"> fileutil::magic::cgen </a> · <a href="tcllib/files/modules/fumagic/filetypes.html"> fileutil::magic::filetype </a> · <a href="tcllib/files/modules/fumagic/rtcore.html"> fileutil::magic::rt </a> · <a href="tcllib/files/modules/snit/snit.html"> snit </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="type_checking"> Type checking </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/valtype_common.html"> valtype::common </a> · <a href="tcllib/files/modules/valtype/cc_amex.html"> valtype::creditcard::amex </a> · <a href="tcllib/files/modules/valtype/cc_discover.html"> valtype::creditcard::discover </a> · <a href="tcllib/files/modules/valtype/cc_mastercard.html"> valtype::creditcard::mastercard </a> · <a href="tcllib/files/modules/valtype/cc_visa.html"> valtype::creditcard::visa </a> · <a href="tcllib/files/modules/valtype/ean13.html"> valtype::gs1::ean13 </a> · <a href="tcllib/files/modules/valtype/iban.html"> valtype::iban </a> · <a href="tcllib/files/modules/valtype/imei.html"> valtype::imei </a> · <a href="tcllib/files/modules/valtype/isbn.html"> valtype::isbn </a> · <a href="tcllib/files/modules/valtype/luhn.html"> valtype::luhn </a> · <a href="tcllib/files/modules/valtype/luhn5.html"> valtype::luhn5 </a> · <a href="tcllib/files/modules/valtype/usnpi.html"> valtype::usnpi </a> · <a href="tcllib/files/modules/valtype/verhoeff.html"> valtype::verhoeff </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cU">Keywords: U</a> </th></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uevent"> uevent </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/hook/hook.html"> hook </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="unbind"> unbind </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uev/uevent.html"> uevent </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uncapitalize"> uncapitalize </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/textutil/textutil_string.html"> textutil::string </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="undenting"> undenting </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/textutil/adjust.html"> textutil::adjust </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="unicode"> unicode </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/stringprep/stringprep.html"> stringprep </a> · <a href="tcllib/files/modules/stringprep/stringprep_data.html"> stringprep::data </a> · <a href="tcllib/files/modules/stringprep/unicode.html"> unicode </a> · <a href="tcllib/files/modules/stringprep/unicode_data.html"> unicode::data </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="union"> union </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/struct/disjointset.html"> struct::disjointset </a> · <a href="tcllib/files/modules/struct/struct_set.html"> struct::set </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="unit"> unit </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/units/units.html"> units </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="unknown_hooking"> unknown hooking </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/namespacex/namespacex.html"> namespacex </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="untie"> untie </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/tie/tie_std.html"> tie </a> · <a href="tcllib/files/modules/tie/tie.html"> tie </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="update"> update </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/coroutine/tcllib_coroutine.html"> coroutine </a> · <a href="tcllib/files/modules/coroutine/coro_auto.html"> coroutine::auto </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uri"> uri </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uri/uri.html"> uri </a> · <a href="tcllib/files/modules/uri/urn-scheme.html"> uri_urn </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="url"> url </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/doctools2idx/idx_container.html"> doctools::idx </a> · <a href="tcllib/files/modules/doctools2idx/idx_export.html"> doctools::idx::export </a> · <a href="tcllib/files/modules/doctools2idx/idx_import.html"> doctools::idx::import </a> · <a href="tcllib/files/modules/doctools2toc/toc_export.html"> doctools::toc::export </a> · <a href="tcllib/files/modules/doctools2toc/toc_import.html"> doctools::toc::import </a> · <a href="tcllib/files/modules/map/map_geocode_nominatim.html"> map::geocode::nominatim </a> · <a href="tcllib/files/modules/map/map_slippy_fetcher.html"> map::slippy::fetcher </a> · <a href="tcllib/files/modules/uri/uri.html"> uri </a> · <a href="tcllib/files/modules/uri/urn-scheme.html"> uri_urn </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="urn"> urn </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uri/urn-scheme.html"> uri_urn </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="us_npi"> US-NPI </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/usnpi.html"> valtype::usnpi </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="utilities"> utilities </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/namespacex/namespacex.html"> namespacex </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uuencode"> uuencode </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/base64/uuencode.html"> uuencode </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uuid"> UUID </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uuid/uuid.html"> uuid </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cV">Keywords: V</a> </th></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="validation"> Validation </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/valtype_common.html"> valtype::common </a> · <a href="tcllib/files/modules/valtype/cc_amex.html"> valtype::creditcard::amex </a> · <a href="tcllib/files/modules/valtype/cc_discover.html"> valtype::creditcard::discover </a> · <a href="tcllib/files/modules/valtype/cc_mastercard.html"> valtype::creditcard::mastercard </a> · <a href="tcllib/files/modules/valtype/cc_visa.html"> valtype::creditcard::visa </a> · <a href="tcllib/files/modules/valtype/ean13.html"> valtype::gs1::ean13 </a> · <a href="tcllib/files/modules/valtype/iban.html"> valtype::iban </a> · <a href="tcllib/files/modules/valtype/imei.html"> valtype::imei </a> · <a href="tcllib/files/modules/valtype/isbn.html"> valtype::isbn </a> · <a href="tcllib/files/modules/valtype/luhn.html"> valtype::luhn </a> · <a href="tcllib/files/modules/valtype/luhn5.html"> valtype::luhn5 </a> · <a href="tcllib/files/modules/valtype/usnpi.html"> valtype::usnpi </a> · <a href="tcllib/files/modules/valtype/verhoeff.html"> valtype::verhoeff </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="value_checking"> Value checking </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/valtype_common.html"> valtype::common </a> · <a href="tcllib/files/modules/valtype/cc_amex.html"> valtype::creditcard::amex </a> · <a href="tcllib/files/modules/valtype/cc_discover.html"> valtype::creditcard::discover </a> · <a href="tcllib/files/modules/valtype/cc_mastercard.html"> valtype::creditcard::mastercard </a> · <a href="tcllib/files/modules/valtype/cc_visa.html"> valtype::creditcard::visa </a> · <a href="tcllib/files/modules/valtype/ean13.html"> valtype::gs1::ean13 </a> · <a href="tcllib/files/modules/valtype/iban.html"> valtype::iban </a> · <a href="tcllib/files/modules/valtype/imei.html"> valtype::imei </a> · <a href="tcllib/files/modules/valtype/isbn.html"> valtype::isbn </a> · <a href="tcllib/files/modules/valtype/luhn.html"> valtype::luhn </a> · <a href="tcllib/files/modules/valtype/luhn5.html"> valtype::luhn5 </a> · <a href="tcllib/files/modules/valtype/usnpi.html"> valtype::usnpi </a> · <a href="tcllib/files/modules/valtype/verhoeff.html"> valtype::verhoeff </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="vectors"> vectors </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/math/linalg.html"> math::linearalgebra </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="verhoeff"> verhoeff </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/verhoeff.html"> valtype::verhoeff </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="vertex"> vertex </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/struct/graph.html"> struct::graph </a> · <a href="tcllib/files/modules/struct/graphops.html"> struct::graph::op </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="vertex_cover"> vertex cover </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/struct/graphops.html"> struct::graph::op </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="virtual_channel"> virtual channel </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/virtchannel_base/cat.html"> tcl::chan::cat </a> · <a href="tcllib/files/modules/virtchannel_core/core.html"> tcl::chan::core </a> · <a href="tcllib/files/modules/virtchannel_core/events.html"> tcl::chan::events </a> · <a href="tcllib/files/modules/virtchannel_base/facade.html"> tcl::chan::facade </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_fifo.html"> tcl::chan::fifo </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_fifo2.html"> tcl::chan::fifo2 </a> · <a href="tcllib/files/modules/virtchannel_base/halfpipe.html"> tcl::chan::halfpipe </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_memchan.html"> tcl::chan::memchan </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_null.html"> tcl::chan::null </a> · <a href="tcllib/files/modules/virtchannel_base/nullzero.html"> tcl::chan::nullzero </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_random.html"> tcl::chan::random </a> · <a href="tcllib/files/modules/virtchannel_base/std.html"> tcl::chan::std </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_string.html"> tcl::chan::string </a> · <a href="tcllib/files/modules/virtchannel_base/textwindow.html"> tcl::chan::textwindow </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_variable.html"> tcl::chan::variable </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_zero.html"> tcl::chan::zero </a> · <a href="tcllib/files/modules/virtchannel_base/randseed.html"> tcl::randomseed </a> · <a href="tcllib/files/modules/virtchannel_transform/adler32.html"> tcl::transform::adler32 </a> · <a href="tcllib/files/modules/virtchannel_transform/vt_base64.html"> tcl::transform::base64 </a> · <a href="tcllib/files/modules/virtchannel_core/transformcore.html"> tcl::transform::core </a> · <a href="tcllib/files/modules/virtchannel_transform/vt_counter.html"> tcl::transform::counter </a> · <a href="tcllib/files/modules/virtchannel_transform/vt_crc32.html"> tcl::transform::crc32 </a> · <a href="tcllib/files/modules/virtchannel_transform/hex.html"> tcl::transform::hex </a> · <a href="tcllib/files/modules/virtchannel_transform/identity.html"> tcl::transform::identity </a> · <a href="tcllib/files/modules/virtchannel_transform/limitsize.html"> tcl::transform::limitsize </a> · <a href="tcllib/files/modules/virtchannel_transform/observe.html"> tcl::transform::observe </a> · <a href="tcllib/files/modules/virtchannel_transform/vt_otp.html"> tcl::transform::otp </a> · <a href="tcllib/files/modules/virtchannel_transform/rot.html"> tcl::transform::rot </a> · <a href="tcllib/files/modules/virtchannel_transform/spacer.html"> tcl::transform::spacer </a> · <a href="tcllib/files/modules/virtchannel_transform/tcllib_zlib.html"> tcl::transform::zlib </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="virtual_machine"> virtual machine </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/grammar_me/me_cpu.html"> grammar::me::cpu </a> · <a href="tcllib/files/modules/grammar_me/me_cpucore.html"> grammar::me::cpu::core </a> · <a href="tcllib/files/modules/grammar_me/gasm.html"> grammar::me::cpu::gasm </a> · <a href="tcllib/files/modules/grammar_me/me_tcl.html"> grammar::me::tcl </a> · <a href="tcllib/files/modules/grammar_me/me_intro.html"> grammar::me_intro </a> · <a href="tcllib/files/modules/grammar_me/me_vm.html"> grammar::me_vm </a> · <a href="tcllib/files/modules/grammar_peg/peg_interp.html"> grammar::peg::interp </a> · <a href="tcllib/files/modules/pt/pt_param.html"> pt::param </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="visa"> VISA </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/cc_visa.html"> valtype::creditcard::visa </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="vwait"> vwait </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/coroutine/tcllib_coroutine.html"> coroutine </a> · <a href="tcllib/files/modules/coroutine/coro_auto.html"> coroutine::auto </a> · <a href="tcllib/files/modules/smtpd/smtpd.html"> smtpd </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cW">Keywords: W</a> </th></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="wais"> wais </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uri/uri.html"> uri </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="widget"> widget </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/snit/snit.html"> snit </a> · <a href="tcllib/files/modules/snit/snitfaq.html"> snitfaq </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="widget_adaptors"> widget adaptors </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/snit/snit.html"> snit </a> · <a href="tcllib/files/modules/snit/snitfaq.html"> snitfaq </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="wiki"> wiki </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/doctools/docidx.html"> doctools::idx </a> · <a href="tcllib/files/modules/doctools2idx/idx_container.html"> doctools::idx </a> · <a href="tcllib/files/modules/doctools2idx/idx_export.html"> doctools::idx::export </a> · <a href="tcllib/files/modules/doctools2idx/idx_export_wiki.html"> doctools::idx::export::wiki </a> · <a href="tcllib/files/modules/doctools2toc/toc_container.html"> doctools::toc </a> · <a href="tcllib/files/modules/doctools/doctoc.html"> doctools::toc </a> · <a href="tcllib/files/modules/doctools2toc/toc_export.html"> doctools::toc::export </a> · <a href="tcllib/files/modules/doctools2toc/toc_export_wiki.html"> doctools::toc::export::wiki </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="word"> word </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/doctools2base/tcl_parse.html"> doctools::tcl::parse </a> · <a href="tcllib/files/modules/wip/wip.html"> wip </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="www"> WWW </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/httpd/httpd.html"> tool </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="www"> www </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uri/uri.html"> uri </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cX">Keywords: X</a> </th></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="x_208"> x.208 </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/asn/asn.html"> asn </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="x_209"> x.209 </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/asn/asn.html"> asn </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="x_500"> x.500 </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/ldap/ldap.html"> ldap </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xgoogletoken"> XGoogleToken </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/sasl/gtoken.html"> SASL::XGoogleToken </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xml"> xml </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/amazon-s3/xsxp.html"> xsxp </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xor"> xor </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/virtchannel_transform/vt_otp.html"> tcl::transform::otp </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xpath"> XPath </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/treeql/treeql.html"> treeql </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xslt"> XSLT </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/treeql/treeql.html"> treeql </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cY">Keywords: Y</a> </th></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="yaml"> yaml </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/yaml/huddle.html"> huddle </a> · <a href="tcllib/files/modules/yaml/yaml.html"> yaml </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="ydecode"> ydecode </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/base64/yencode.html"> yencode </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="yenc"> yEnc </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/base64/yencode.html"> yencode </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="yencode"> yencode </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/base64/yencode.html"> yencode </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cZ">Keywords: Z</a> </th></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="zero"> zero </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/virtchannel_base/nullzero.html"> tcl::chan::nullzero </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_zero.html"> tcl::chan::zero </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="zip"> zip </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/zip/decode.html"> zipfile::decode </a> · <a href="tcllib/files/modules/zip/encode.html"> zipfile::encode </a> · <a href="tcllib/files/modules/zip/mkzip.html"> zipfile::mkzip </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="zlib"> zlib </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/virtchannel_transform/tcllib_zlib.html"> tcl::transform::zlib </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="zoom"> zoom </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/map/map_slippy.html"> map::slippy </a> · <a href="tcllib/files/modules/map/map_slippy_cache.html"> map::slippy::cache </a> · <a href="tcllib/files/modules/map/map_slippy_fetcher.html"> map::slippy::fetcher </a> </td></tr> </table> |
Added embedded/www/tcllib/files/modules/clay/clay.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | <!DOCTYPE html><html><head> <title>clay - Clay Framework</title> <style type="text/css"><!-- HTML { background: #FFFFFF; color: black; } BODY { background: #FFFFFF; color: black; } DIV.doctools { margin-left: 10%; margin-right: 10%; } DIV.doctools H1,DIV.doctools H2 { margin-left: -5%; } H1, H2, H3, H4 { margin-top: 1em; font-family: sans-serif; font-size: large; color: #005A9C; background: transparent; text-align: left; } H1.doctools_title { text-align: center; } UL,OL { margin-right: 0em; margin-top: 3pt; margin-bottom: 3pt; } UL LI { list-style: disc; } OL LI { list-style: decimal; } DT { padding-top: 1ex; } UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL { font: normal 12pt/14pt sans-serif; list-style: none; } LI.doctools_section, LI.doctools_subsection { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } PRE { display: block; font-family: monospace; white-space: pre; margin: 0%; padding-top: 0.5ex; padding-bottom: 0.5ex; padding-left: 1ex; padding-right: 1ex; width: 100%; } PRE.doctools_example { color: black; background: #f5dcb3; border: 1px solid black; } UL.doctools_requirements LI, UL.doctools_syntax LI { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } DIV.doctools_synopsis { color: black; background: #80ffff; border: 1px solid black; font-family: serif; margin-top: 1em; margin-bottom: 1em; } UL.doctools_syntax { margin-top: 1em; border-top: 1px solid black; } UL.doctools_requirements { margin-bottom: 1em; border-bottom: 1px solid black; } --></style> </head> <!-- Generated from file 'clay.man' by tcllib/doctools with format 'html' --> <!-- Copyright &copy; 2018 Sean Woods &lt;[email protected]&gt; --> <!-- clay.n --> <body><div class="doctools"> <h1 class="doctools_title">clay(n) 0.3 clay "Clay Framework"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>clay - A minimalist framework for large scale OO Projects</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a> <ul> <li class="doctools_subsection"><a href="#subsection1">Structured Data</a></li> <li class="doctools_subsection"><a href="#subsection2">Clay Dialect</a></li> <li class="doctools_subsection"><a href="#subsection3">Method Delegation</a></li> </ul> </li> <li class="doctools_section"><a href="#section2">Commands</a></li> <li class="doctools_section"><a href="#section3">Classes</a> <ul> <li class="doctools_subsection"><a href="#subsection4">Class oo::class</a></li> <li class="doctools_subsection"><a href="#subsection5">Class oo::object</a></li> <li class="doctools_subsection"><a href="#subsection6">Class clay::object</a></li> <li class="doctools_subsection"><a href="#subsection7">Class clay::doctool</a></li> </ul> </li> <li class="doctools_section"><a href="#section4">AUTHORS</a></li> <li class="doctools_section"><a href="#section5">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.6</b></li> <li>package require <b class="pkgname">uuid</b></li> <li>package require <b class="pkgname">oo::dialect</b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1">proc <b class="cmd">putb</b> <span class="opt">?<i class="arg">map</i>?</span> <i class="arg">text</i></a></li> <li><a href="#2">proc <b class="cmd">clay::ancestors</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#3">proc <b class="cmd">clay::args_to_dict</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#4">proc <b class="cmd">clay::args_to_options</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#5">proc <b class="cmd">clay::dictmerge</b> <i class="arg">varname</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#6">proc <b class="cmd">clay::_dictmerge</b> <i class="arg">a</i> <i class="arg">b</i></a></li> <li><a href="#7">proc <b class="cmd">clay::dictputb</b> <i class="arg">dict</i></a></li> <li><a href="#8">proc <b class="cmd">clay::_dictputb</b> <i class="arg">leaf</i> <i class="arg">level</i> <i class="arg">varname</i> <i class="arg">dict</i></a></li> <li><a href="#9">proc <b class="cmd">clay::dynamic_arguments</b> <i class="arg">ensemble</i> <i class="arg">method</i> <i class="arg">arglist</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#10">proc <b class="cmd">clay::dynamic_wrongargs_message</b> <i class="arg">arglist</i></a></li> <li><a href="#11">proc <b class="cmd">clay::is_dict</b> <i class="arg">d</i></a></li> <li><a href="#12">proc <b class="cmd">clay::is_null</b> <i class="arg">value</i></a></li> <li><a href="#13">proc <b class="cmd">clay::leaf</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#14">proc <b class="cmd">clay::path</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#15">proc <b class="cmd">clay::script_path</b></a></li> <li><a href="#16">proc <b class="cmd">clay::NSNormalize</b> <i class="arg">qualname</i></a></li> <li><a href="#17">proc <b class="cmd">clay::uuid_generate</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#18">proc <b class="cmd">clay::dynamic_methods</b> <i class="arg">class</i></a></li> <li><a href="#19">proc <b class="cmd">clay::dynamic_methods_class</b> <i class="arg">thisclass</i></a></li> <li><a href="#20">proc <b class="cmd">clay::define::Array</b> <i class="arg">name</i> <span class="opt">?<i class="arg">values</i> <b class="const"></b>?</span></a></li> <li><a href="#21">proc <b class="cmd">clay::define::component</b> <i class="arg">name</i> <i class="arg">info</i></a></li> <li><a href="#22">proc <b class="cmd">clay::define::constructor</b> <i class="arg">arglist</i> <i class="arg">rawbody</i></a></li> <li><a href="#23">proc <b class="cmd">clay::define::class_method</b> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></li> <li><a href="#24">proc <b class="cmd">clay::define::clay</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#25">proc <b class="cmd">clay::define::destructor</b> <i class="arg">rawbody</i></a></li> <li><a href="#26">proc <b class="cmd">clay::define::Dict</b> <i class="arg">name</i> <span class="opt">?<i class="arg">values</i> <b class="const"></b>?</span></a></li> <li><a href="#27">proc <b class="cmd">clay::define::Variable</b> <i class="arg">name</i> <span class="opt">?<i class="arg">default</i> <b class="const"></b>?</span></a></li> <li><a href="#28">proc <b class="cmd">clay::object_create</b> <i class="arg">objname</i> <span class="opt">?<i class="arg">class</i> <b class="const"></b>?</span></a></li> <li><a href="#29">proc <b class="cmd">clay::object_rename</b> <i class="arg">object</i> <i class="arg">newname</i></a></li> <li><a href="#30">proc <b class="cmd">clay::object_destroy</b> <i class="arg">objname</i></a></li> <li><a href="#31">proc <b class="cmd">clay::ensemble_methodbody</b> <i class="arg">ensemble</i> <i class="arg">einfo</i></a></li> <li><a href="#32">proc <b class="cmd">clay::define::Ensemble</b> <i class="arg">rawmethod</i> <i class="arg">arglist</i> <i class="arg">body</i></a></li> <li><a href="#33">proc <b class="cmd">clay::cat</b> <i class="arg">fname</i></a></li> <li><a href="#34">proc <b class="cmd">clay::docstrip</b> <i class="arg">text</i></a></li> <li><a href="#35">method <b class="cmd">clay ancestors</b></a></li> <li><a href="#36">method <b class="cmd">clay dump</b></a></li> <li><a href="#37">method <b class="cmd">clay get</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#38">method <b class="cmd">clay merge</b> <i class="arg">dict</i> <span class="opt">?<b class="option">dict...</b>?</span></a></li> <li><a href="#39">method <b class="cmd">clay replace</b> <i class="arg">dictionary</i></a></li> <li><a href="#40">method <b class="cmd">clay search</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#41">method <b class="cmd">clay set</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span> <i class="arg">value</i></a></li> <li><a href="#42">method <b class="cmd">clay ancestors</b></a></li> <li><a href="#43">method <b class="cmd">clay cget</b> <i class="arg">field</i></a></li> <li><a href="#44">method <b class="cmd">clay delegate</b> <span class="opt">?<i class="arg">stub</i>?</span> <span class="opt">?<i class="arg">object</i>?</span></a></li> <li><a href="#45">method <b class="cmd">clay dump</b></a></li> <li><a href="#46">method <b class="cmd">clay ensemble_map</b></a></li> <li><a href="#47">method <b class="cmd">clay eval</b> <i class="arg">script</i></a></li> <li><a href="#48">method <b class="cmd">clay evolve</b></a></li> <li><a href="#49">method <b class="cmd">clay exists</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#50">method <b class="cmd">clay flush</b></a></li> <li><a href="#51">method <b class="cmd">clay forward</b> <i class="arg">method</i> <i class="arg">object</i></a></li> <li><a href="#52">method <b class="cmd">clay get</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#53">method <b class="cmd">clay leaf</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#54">method <b class="cmd">clay merge</b> <i class="arg">dict</i> <span class="opt">?<b class="option">dict...</b>?</span></a></li> <li><a href="#55">method <b class="cmd">clay mixin</b> <i class="arg">class</i> <span class="opt">?<b class="option">class...</b>?</span></a></li> <li><a href="#56">method <b class="cmd">clay mixinmap</b> <span class="opt">?<i class="arg">stub</i>?</span> <span class="opt">?<i class="arg">classes</i>?</span></a></li> <li><a href="#57">method <b class="cmd">clay provenance</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#58">method <b class="cmd">clay replace</b> <i class="arg">dictionary</i></a></li> <li><a href="#59">method <b class="cmd">clay source</b> <i class="arg">filename</i></a></li> <li><a href="#60">method <b class="cmd">clay set</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span> <i class="arg">value</i></a></li> <li><a href="#61">method <b class="cmd">InitializePublic</b></a></li> <li><a href="#62">method <b class="cmd">InitializePublic</b></a></li> <li><a href="#63">method <b class="cmd">constructor</b></a></li> <li><a href="#64">method <b class="cmd">arglist</b> <i class="arg">arglist</i></a></li> <li><a href="#65">method <b class="cmd">comment</b> <i class="arg">block</i></a></li> <li><a href="#66">method <b class="cmd">keyword.Class</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">body</i></a></li> <li><a href="#67">method <b class="cmd">keyword.class</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">body</i></a></li> <li><a href="#68">method <b class="cmd">keyword.class_method</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#69">method <b class="cmd">keyword.method</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#70">method <b class="cmd">keyword.proc</b> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></li> <li><a href="#71">method <b class="cmd">reset</b></a></li> <li><a href="#72">method <b class="cmd">Main</b></a></li> <li><a href="#73">method <b class="cmd">section.method</b> <i class="arg">keyword</i> <i class="arg">method</i> <i class="arg">minfo</i></a></li> <li><a href="#74">method <b class="cmd">section.class</b> <i class="arg">class_name</i> <i class="arg">class_info</i></a></li> <li><a href="#75">method <b class="cmd">section.command</b> <i class="arg">procinfo</i></a></li> <li><a href="#76">method <b class="cmd">manpage</b> <span class="opt">?<b class="option">header <em>value</em></b>?</span> <span class="opt">?<b class="option">footer <em>value</em></b>?</span> <span class="opt">?<b class="option">authors <em>list</em></b>?</span></a></li> <li><a href="#77">method <b class="cmd">scan_text</b> <i class="arg">text</i></a></li> <li><a href="#78">method <b class="cmd">scan_file</b> <i class="arg">filename</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>Clay introduces a method ensemble to both <b class="class">oo::class</b> and <b class="class">oo::object</b> called clay. This ensemble handles all of the high level interactions within the framework. Clay stores structured data. Clan manages method delegation. Clay has facilities to manage the complex interactions that come about with mixins.</p> <p>The central concept is that inside of every object and class (which are actually objects too) is a dict called clay. What is stored in that dict is left to the imagination. But because this dict is exposed via a public method, we can share structured data between object, classes, and mixins.</p> <div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Structured Data</a></h3> <p>Clay uses a standardized set of method interactions and introspection that TclOO already provides to perform on-the-fly searches. On-the-fly searches mean that the data is never stale, and we avoid many of the sorts of collisions that would arise when objects start mixing in other classes during operation.</p> <p>The <b class="method">clay</b> methods for both classes and objects have a get and a set method. For objects, get will search through the local clay dict. If the requested leaf is not found, or the query is for a branch, the system will then begin to poll the clay methods of all of the class that implements the object, all of that classes’ ancestors, as well as all of the classes that have been mixed into this object, and all of their ancestors.</p> <p>Intended branches on a tree end with a directory slash (/). Intended leaves are left unadorned. This is a guide for the tool that builds the search results to know what parts of a dict are intended to be branches and which are intended to be leaves. For simple cases, branch marking can be ignored:</p> <pre class="doctools_example"> ::oo::class create ::foo { } ::foo clay set property/ color blue ::foo clay set property/ shape round set A [::foo new] $A clay get property/ {color blue shape round} $A clay set property/ shape square $A clay get property/ {color blue shape square} </pre> <p>But when you start storing blocks of text, guessing what field is a dict and what isn’t gets messy:</p> <pre class="doctools_example"> ::foo clay set description {A generic thing of designated color and shape} $A clay get description {A generic thing of designated color and shape} Without a convention for discerning branches for leaves what should have been a value can be accidentally parsed as a dictionary, and merged with all of the other values that were never intended to be merge. Here is an example of it all going wrong: ::oo::class create ::foo { } # Add description as a leaf ::foo clay set description {A generic thing of designated color and shape} # Add description as a branch ::foo clay set description/ {A generic thing of designated color and shape} ::oo::class create ::bar { superclass foo } # Add description as a leaf ::bar clay set description {A drinking establishment of designated color and shape and size} # Add description as a branch ::bar clay set description/ {A drinking establishment of designated color and shape and size} set B [::bar new] # As a leaf we get the value verbatim from he nearest ancestor $B clay get description {A drinking establishment of designated color and shape and size} # As a branch we get a recursive merge $B clay get description/ {A drinking establishment of designated color and size thing of} </pre> </div> <div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">Clay Dialect</a></h3> <p>Clay is built using the oo::dialect module from Tcllib. oo::dialect allows you to either add keywords directly to clay, or to create your own metaclass and keyword set using Clay as a foundation. For details on the keywords and what they do, consult the functions in the ::clay::define namespace.</p> </div> <div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Method Delegation</a></h3> <p>Method Delegation It is sometimes useful to have an external object that can be invoked as if it were a method of the object. Clay provides a delegate ensemble method to perform that delegation, as well as introspect which methods are delegated in that manner. All delegated methods are marked with html-like tag markings (< >) around them.</p> <pre class="doctools_example"> ::clay::define counter { Variable counter 0 method incr {{howmuch 1}} { my variable counter incr counter $howmuch } method value {} { my variable counter return $counter } method reset {} { my variable counter set counter 0 } } ::clay::define example { variable buffer constructor {} { # Build a counter object set obj [namespace current]::counter ::counter create $obj # Delegate the counter my delegate <counter> $obj } method line {text} { my <counter> incr append buffer $text } } set A [example new] $A line {Who’s line is it anyway?} $A <counter> value 1 </pre> </div> </div> <div id="section2" class="doctools_section"><h2><a name="section2">Commands</a></h2> <dl class="doctools_definitions"> <dt><a name="1">proc <b class="cmd">putb</b> <span class="opt">?<i class="arg">map</i>?</span> <i class="arg">text</i></a></dt> <dd><p>Append a line of text to a variable. Optionally apply a string mapping.</p></dd> <dt><a name="2">proc <b class="cmd">clay::ancestors</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="3">proc <b class="cmd">clay::args_to_dict</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="4">proc <b class="cmd">clay::args_to_options</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="5">proc <b class="cmd">clay::dictmerge</b> <i class="arg">varname</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="6">proc <b class="cmd">clay::_dictmerge</b> <i class="arg">a</i> <i class="arg">b</i></a></dt> <dd></dd> <dt><a name="7">proc <b class="cmd">clay::dictputb</b> <i class="arg">dict</i></a></dt> <dd></dd> <dt><a name="8">proc <b class="cmd">clay::_dictputb</b> <i class="arg">leaf</i> <i class="arg">level</i> <i class="arg">varname</i> <i class="arg">dict</i></a></dt> <dd></dd> <dt><a name="9">proc <b class="cmd">clay::dynamic_arguments</b> <i class="arg">ensemble</i> <i class="arg">method</i> <i class="arg">arglist</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="10">proc <b class="cmd">clay::dynamic_wrongargs_message</b> <i class="arg">arglist</i></a></dt> <dd></dd> <dt><a name="11">proc <b class="cmd">clay::is_dict</b> <i class="arg">d</i></a></dt> <dd></dd> <dt><a name="12">proc <b class="cmd">clay::is_null</b> <i class="arg">value</i></a></dt> <dd></dd> <dt><a name="13">proc <b class="cmd">clay::leaf</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="14">proc <b class="cmd">clay::path</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="15">proc <b class="cmd">clay::script_path</b></a></dt> <dd></dd> <dt><a name="16">proc <b class="cmd">clay::NSNormalize</b> <i class="arg">qualname</i></a></dt> <dd></dd> <dt><a name="17">proc <b class="cmd">clay::uuid_generate</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="18">proc <b class="cmd">clay::dynamic_methods</b> <i class="arg">class</i></a></dt> <dd></dd> <dt><a name="19">proc <b class="cmd">clay::dynamic_methods_class</b> <i class="arg">thisclass</i></a></dt> <dd></dd> <dt><a name="20">proc <b class="cmd">clay::define::Array</b> <i class="arg">name</i> <span class="opt">?<i class="arg">values</i> <b class="const"></b>?</span></a></dt> <dd><p>New OO Keywords for clay</p></dd> <dt><a name="21">proc <b class="cmd">clay::define::component</b> <i class="arg">name</i> <i class="arg">info</i></a></dt> <dd></dd> <dt><a name="22">proc <b class="cmd">clay::define::constructor</b> <i class="arg">arglist</i> <i class="arg">rawbody</i></a></dt> <dd></dd> <dt><a name="23">proc <b class="cmd">clay::define::class_method</b> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="24">proc <b class="cmd">clay::define::clay</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="25">proc <b class="cmd">clay::define::destructor</b> <i class="arg">rawbody</i></a></dt> <dd></dd> <dt><a name="26">proc <b class="cmd">clay::define::Dict</b> <i class="arg">name</i> <span class="opt">?<i class="arg">values</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="27">proc <b class="cmd">clay::define::Variable</b> <i class="arg">name</i> <span class="opt">?<i class="arg">default</i> <b class="const"></b>?</span></a></dt> <dd><p>This keyword can also be expressed:</p> <pre class="doctools_example">property variable NAME {default DEFAULT}</pre> <p>Variables registered in the variable property are also initialized (if missing) when the object changes class via the <em>morph</em> method.</p></dd> <dt><a name="28">proc <b class="cmd">clay::object_create</b> <i class="arg">objname</i> <span class="opt">?<i class="arg">class</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="29">proc <b class="cmd">clay::object_rename</b> <i class="arg">object</i> <i class="arg">newname</i></a></dt> <dd></dd> <dt><a name="30">proc <b class="cmd">clay::object_destroy</b> <i class="arg">objname</i></a></dt> <dd></dd> <dt><a name="31">proc <b class="cmd">clay::ensemble_methodbody</b> <i class="arg">ensemble</i> <i class="arg">einfo</i></a></dt> <dd></dd> <dt><a name="32">proc <b class="cmd">clay::define::Ensemble</b> <i class="arg">rawmethod</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="33">proc <b class="cmd">clay::cat</b> <i class="arg">fname</i></a></dt> <dd><p>Concatenate a file</p></dd> <dt><a name="34">proc <b class="cmd">clay::docstrip</b> <i class="arg">text</i></a></dt> <dd><p>Strip the global comments from tcl code. Used to prevent the documentation markup comments from clogging up files intended for distribution in machine readable format.</p></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Classes</a></h2> <div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Class oo::class</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="35">method <b class="cmd">clay ancestors</b></a></dt> <dd><p>Return this class and all ancestors in search order.</p></dd> <dt><a name="36">method <b class="cmd">clay dump</b></a></dt> <dd><p>Return a complete dump of this object's clay data, but only this object's clay data.</p></dd> <dt><a name="37">method <b class="cmd">clay get</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Pull a chunk of data from the clay system. If the last element of <em>path</em> is a branch (ends in a slash /), returns a recursive merge of all data from this object and it's constituent classes of the data in that branch. If the last element is a leaf, search this object for a matching leaf, or search all constituent classes for a matching leaf and return the first value found. If no value is found, returns an empty string.</p></dd> <dt><a name="38">method <b class="cmd">clay merge</b> <i class="arg">dict</i> <span class="opt">?<b class="option">dict...</b>?</span></a></dt> <dd><p>Recursively merge the dictionaries given into the object's local clay storage.</p></dd> <dt><a name="39">method <b class="cmd">clay replace</b> <i class="arg">dictionary</i></a></dt> <dd><p>Replace the contents of the internal clay storage with the dictionary given.</p></dd> <dt><a name="40">method <b class="cmd">clay search</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Return the first matching value for the path in either this class's clay data or one of its ancestors</p></dd> <dt><a name="41">method <b class="cmd">clay set</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span> <i class="arg">value</i></a></dt> <dd><p>Merge the conents of <b class="const">value</b> with the object's clay storage at <b class="const">path</b>.</p></dd> </dl> </div> <div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Class oo::object</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="42">method <b class="cmd">clay ancestors</b></a></dt> <dd><p>Return the class this object belongs to, all classes mixed into this object, and all ancestors of those classes in search order.</p></dd> <dt><a name="43">method <b class="cmd">clay cget</b> <i class="arg">field</i></a></dt> <dd><p>Pull a value from either the object's clay structure or one of its constituent classes that matches the field name. The order of search us:</p> <p>1. The as a value in local dict variable config</p> <p>2. The as a value in local dict variable clay</p> <p>3. As a leaf in any ancestor as a root of the clay tree</p> <p>4. As a leaf in any ancestor under the const/ branch of the clay tree</p></dd> <dt><a name="44">method <b class="cmd">clay delegate</b> <span class="opt">?<i class="arg">stub</i>?</span> <span class="opt">?<i class="arg">object</i>?</span></a></dt> <dd><p>Introspect or control method delegation. With no arguments, the method will return a key/value list of stubs and objects. With just the <i class="arg">stub</i> argument, the method will return the object (if any) attached to the stub. With a <i class="arg">stub</i> and an <i class="arg">object</i> this command will forward all calls to the method <i class="arg">stub</i> to the <i class="arg">object</i>.</p></dd> <dt><a name="45">method <b class="cmd">clay dump</b></a></dt> <dd><p>Return a complete dump of this object's clay data, as well as the data from all constituent classes recursively blended in.</p></dd> <dt><a name="46">method <b class="cmd">clay ensemble_map</b></a></dt> <dd><p>Return a dictionary describing the method ensembles to be assembled for this object</p></dd> <dt><a name="47">method <b class="cmd">clay eval</b> <i class="arg">script</i></a></dt> <dd><p>Evaluated a script in the namespace of this object</p></dd> <dt><a name="48">method <b class="cmd">clay evolve</b></a></dt> <dd><p>Trigger the <b class="method">InitializePublic</b> private method</p></dd> <dt><a name="49">method <b class="cmd">clay exists</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Returns 1 if <em>path</em> exists in either the object's clay data. Values greater than one indicate the element exists in one of the object's constituent classes. A value of zero indicates the path could not be found.</p></dd> <dt><a name="50">method <b class="cmd">clay flush</b></a></dt> <dd><p>Wipe any caches built by the clay implementation</p></dd> <dt><a name="51">method <b class="cmd">clay forward</b> <i class="arg">method</i> <i class="arg">object</i></a></dt> <dd><p>A convenience wrapper for</p> <pre class="doctools_example">oo::objdefine [self] forward {*}$args</pre> </dd> <dt><a name="52">method <b class="cmd">clay get</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Pull a chunk of data from the clay system. If the last element of <em>path</em> is a branch (ends in a slash /), returns a recursive merge of all data from this object and it's constituent classes of the data in that branch. If the last element is a leaf, search this object for a matching leaf, or search all constituent classes for a matching leaf and return the first value found. If no value is found, returns an empty string.</p></dd> <dt><a name="53">method <b class="cmd">clay leaf</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>A modified get which is tailored to pull only leaf elements</p></dd> <dt><a name="54">method <b class="cmd">clay merge</b> <i class="arg">dict</i> <span class="opt">?<b class="option">dict...</b>?</span></a></dt> <dd><p>Recursively merge the dictionaries given into the object's local clay storage.</p></dd> <dt><a name="55">method <b class="cmd">clay mixin</b> <i class="arg">class</i> <span class="opt">?<b class="option">class...</b>?</span></a></dt> <dd><p>Perform [oo::objdefine [self] mixin] on this object, with a few additional rules: Prior to the call, for any class was previously mixed in, but not in the new result, execute the script registered to mixin/ unmap-script (if given.) For all new classes, that were not present prior to this call, after the native TclOO mixin is invoked, execute the script registered to mixin/ map-script (if given.) Fall all classes that are now present and “mixed in”, execute the script registered to mixin/ react-script (if given.)</p></dd> <dt><a name="56">method <b class="cmd">clay mixinmap</b> <span class="opt">?<i class="arg">stub</i>?</span> <span class="opt">?<i class="arg">classes</i>?</span></a></dt> <dd><p>With no arguments returns the map of stubs and classes mixed into the current object. When only stub is given, returns the classes mixed in on that stub. When stub and classlist given, replace the classes currently on that stub with the given classes and invoke clay mixin on the new matrix of mixed in classes.</p></dd> <dt><a name="57">method <b class="cmd">clay provenance</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Return either <b class="const">self</b> if that path exists in the current object, or return the first class (if any) along the clay search path which contains that element.</p></dd> <dt><a name="58">method <b class="cmd">clay replace</b> <i class="arg">dictionary</i></a></dt> <dd><p>Replace the contents of the internal clay storage with the dictionary given.</p></dd> <dt><a name="59">method <b class="cmd">clay source</b> <i class="arg">filename</i></a></dt> <dd><p>Source the given filename within the object's namespace</p></dd> <dt><a name="60">method <b class="cmd">clay set</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span> <i class="arg">value</i></a></dt> <dd><p>Merge the conents of <b class="const">value</b> with the object's clay storage at <b class="const">path</b>.</p></dd> <dt><a name="61">method <b class="cmd">InitializePublic</b></a></dt> <dd><p>Instantiate variables. Called on object creation and during clay mixin.</p></dd> </dl> </div> <div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Class clay::object</a></h3> <p>clay::object This class is inherited by all classes that have options.</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="62">method <b class="cmd">InitializePublic</b></a></dt> <dd><p>Instantiate variables and build ensemble methods.</p></dd> </dl> </div> <div id="subsection7" class="doctools_subsection"><h3><a name="subsection7">Class clay::doctool</a></h3> <pre class="doctools_example">{ set authors { {John Doe} {[email protected]} {Tom RichardHarry} {[email protected]} } # Create the object ::clay::doctool create AutoDoc set fout [open [file join $moddir module.tcl] w] foreach file [glob [file join $srcdir *.tcl]] { set content [::clay::cat [file join $srcdir $file]] # Scan the file AutoDoc scan_text $content # Strip the comments from the distribution puts $fout [::clay::docstrip $content] } # Write out the manual page set manout [open [file join $moddir module.man] w] dict set arglist header [string map $modmap [::clay::cat [file join $srcdir manual.txt]]] dict set arglist footer [string map $modmap [::clay::cat [file join $srcdir footer.txt]]] dict set arglist authors $authors puts $manout [AutoDoc manpage {*}$arglist] close $manout }</pre> <p>Tool for build scripts to dynamically generate manual files from comments in source code files</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="63">method <b class="cmd">constructor</b></a></dt> <dd></dd> <dt><a name="64">method <b class="cmd">arglist</b> <i class="arg">arglist</i></a></dt> <dd><p>Process an argument list into an informational dict. This method also understands non-positional arguments expressed in the notation of Tip 471 <a href="https://core.tcl-lang.org/tips/doc/trunk/tip/479.md">https://core.tcl-lang.org/tips/doc/trunk/tip/479.md</a>.</p> <p>The output will be a dictionary of all of the fields and whether the fields are <b class="const">positional</b>, <b class="const">mandatory</b>, and whether they have a <b class="const">default</b> value.</p> <p>Example:</p> <pre class="doctools_example"> my arglist {a b {c 10}} > a {positional 1 mandatory 1} b {positional 1 mandatory 1} c {positional 1 mandatory 0 default 10} </pre> </dd> <dt><a name="65">method <b class="cmd">comment</b> <i class="arg">block</i></a></dt> <dd><p>Convert a block of comments into an informational dictionary. If lines in the comment start with a single word ending in a colon, all subsequent lines are appended to a dictionary field of that name. If no fields are given, all of the text is appended to the <b class="const">description</b> field.</p> <p>Example:</p> <pre class="doctools_example"> my comment {Does something cool} > description {Does something cool} my comment { title : Something really cool author : Sean Woods author : John Doe description : This does something really cool! } > description {This does something really cool!} title {Something really cool} author {Sean Woods John Doe} </pre> </dd> <dt><a name="66">method <b class="cmd">keyword.Class</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">body</i></a></dt> <dd><p>Process an oo::objdefine call that modifies the class object itself</p></dd> <dt><a name="67">method <b class="cmd">keyword.class</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">body</i></a></dt> <dd><p>Process an oo::define, clay::define, etc statement.</p></dd> <dt><a name="68">method <b class="cmd">keyword.class_method</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Process a statement for a clay style class method</p></dd> <dt><a name="69">method <b class="cmd">keyword.method</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Process a statement for a tcloo style object method</p></dd> <dt><a name="70">method <b class="cmd">keyword.proc</b> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd><p>Process a proc statement</p></dd> <dt><a name="71">method <b class="cmd">reset</b></a></dt> <dd><p>Reset the state of the object and its embedded coroutine</p></dd> <dt><a name="72">method <b class="cmd">Main</b></a></dt> <dd><p>Main body of the embedded coroutine for the object</p></dd> <dt><a name="73">method <b class="cmd">section.method</b> <i class="arg">keyword</i> <i class="arg">method</i> <i class="arg">minfo</i></a></dt> <dd><p>Generate the manual page text for a method or proc</p></dd> <dt><a name="74">method <b class="cmd">section.class</b> <i class="arg">class_name</i> <i class="arg">class_info</i></a></dt> <dd><p>Generate the manual page text for a class</p></dd> <dt><a name="75">method <b class="cmd">section.command</b> <i class="arg">procinfo</i></a></dt> <dd><p>Generate the manual page text for the commands section</p></dd> <dt><a name="76">method <b class="cmd">manpage</b> <span class="opt">?<b class="option">header <em>value</em></b>?</span> <span class="opt">?<b class="option">footer <em>value</em></b>?</span> <span class="opt">?<b class="option">authors <em>list</em></b>?</span></a></dt> <dd><p>Generate the manual page. Returns the completed text suitable for saving in .man file. The header argument is a block of doctools text to go in before the machine generated section. footer is a block of doctools text to go in after the machine generated section. authors is a list of individual authors and emails in the form of AUTHOR EMAIL ?AUTHOR EMAIL?...</p></dd> <dt><a name="77">method <b class="cmd">scan_text</b> <i class="arg">text</i></a></dt> <dd><p>Scan a block of text</p></dd> <dt><a name="78">method <b class="cmd">scan_file</b> <i class="arg">filename</i></a></dt> <dd><p>Scan a file of text</p></dd> </dl> </div> </div> <div id="section4" class="doctools_section"><h2><a name="section4">AUTHORS</a></h2> <p>Sean Woods <a href="mailto:<[email protected]>">mailto:<[email protected]></a></p> </div> <div id="section5" class="doctools_section"><h2><a name="section5">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>oo</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. Please also report any ideas for enhancements you may have for either package and/or documentation.</p> <p>When proposing code changes, please provide <em>unified diffs</em>, i.e the output of <b class="const">diff -u</b>.</p> <p>Note further that <em>attachments</em> are strongly preferred over inlined patches. Attachments can be made by going to the <b class="const">Edit</b> form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p>TclOO, oo</p> </div> <div id="category" class="doctools_section"><h2><a name="category">Category</a></h2> <p>Programming tools</p> </div> <div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> <p>Copyright © 2018 Sean Woods <[email protected]></p> </div> </div></body></html> |
Changes to embedded/www/tcllib/files/modules/cron/cron.html.
︙ | ︙ | |||
129 130 131 132 133 134 135 | <li><a href="#5"><b class="cmd">::cron::object_coroutine</b> <i class="arg">object</i> <i class="arg">coroutine</i> <i class="arg">?info?</i></a></li> <li><a href="#6"><b class="cmd">::cron::sleep</b> <i class="arg">milliseconds</i></a></li> <li><a href="#7"><b class="cmd">::cron::task delete</b> <i class="arg">process</i></a></li> <li><a href="#8"><b class="cmd">::cron::task exists</b> <i class="arg">process</i></a></li> <li><a href="#9"><b class="cmd">::cron::task info</b> <i class="arg">process</i></a></li> <li><a href="#10"><b class="cmd">::cron::task set</b> <i class="arg">process</i> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">?field...?</i> <i class="arg">?value...?</i></a></li> <li><a href="#11"><b class="cmd">::cron::wake</b> <i class="arg">?who?</i></a></li> | | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | <li><a href="#5"><b class="cmd">::cron::object_coroutine</b> <i class="arg">object</i> <i class="arg">coroutine</i> <i class="arg">?info?</i></a></li> <li><a href="#6"><b class="cmd">::cron::sleep</b> <i class="arg">milliseconds</i></a></li> <li><a href="#7"><b class="cmd">::cron::task delete</b> <i class="arg">process</i></a></li> <li><a href="#8"><b class="cmd">::cron::task exists</b> <i class="arg">process</i></a></li> <li><a href="#9"><b class="cmd">::cron::task info</b> <i class="arg">process</i></a></li> <li><a href="#10"><b class="cmd">::cron::task set</b> <i class="arg">process</i> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">?field...?</i> <i class="arg">?value...?</i></a></li> <li><a href="#11"><b class="cmd">::cron::wake</b> <i class="arg">?who?</i></a></li> <li><a href="#12"><b class="cmd">::cron::clock_step</b> <i class="arg">milliseconds</i></a></li> <li><a href="#13"><b class="cmd">::cron::clock_delay</b> <i class="arg">milliseconds</i></a></li> <li><a href="#14"><b class="cmd">::cron::clock_sleep</b> <i class="arg">seconds</i> <i class="arg">?offset?</i></a></li> <li><a href="#15"><b class="cmd">::cron::clock_set</b> <i class="arg">newtime</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>The <b class="package">cron</b> package provides a Pure-tcl set of tools to allow |
︙ | ︙ | |||
224 225 226 227 228 229 230 | <dt><a name="8"><b class="cmd">::cron::task exists</b> <i class="arg">process</i></a></dt> <dd><p>Returns true if <i class="arg">process</i> is registered with cron.</p></dd> <dt><a name="9"><b class="cmd">::cron::task info</b> <i class="arg">process</i></a></dt> <dd><p>Returns a dict describing <i class="arg">process</i>. See <b class="cmd">::cron::task set</b> for a description of the options.</p></dd> <dt><a name="10"><b class="cmd">::cron::task set</b> <i class="arg">process</i> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">?field...?</i> <i class="arg">?value...?</i></a></dt> <dd><p>If <i class="arg">process</i> does not exist, it is created. Options Include:</p> <dl class="doctools_definitions"> | | | | | | | | | | | | | | | | | | | | | | | | 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 | <dt><a name="8"><b class="cmd">::cron::task exists</b> <i class="arg">process</i></a></dt> <dd><p>Returns true if <i class="arg">process</i> is registered with cron.</p></dd> <dt><a name="9"><b class="cmd">::cron::task info</b> <i class="arg">process</i></a></dt> <dd><p>Returns a dict describing <i class="arg">process</i>. See <b class="cmd">::cron::task set</b> for a description of the options.</p></dd> <dt><a name="10"><b class="cmd">::cron::task set</b> <i class="arg">process</i> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">?field...?</i> <i class="arg">?value...?</i></a></dt> <dd><p>If <i class="arg">process</i> does not exist, it is created. Options Include:</p> <dl class="doctools_definitions"> <dt><b class="cmd"><a href="../../../../index.html#command">command</a></b></dt> <dd><p>If <b class="cmd"><a href="../coroutine/tcllib_coroutine.html">coroutine</a></b> is black, a global command which implements this process. If <b class="cmd"><a href="../coroutine/tcllib_coroutine.html">coroutine</a></b> is not black, the command to invoke to create or recreate the coroutine.</p></dd> <dt><b class="cmd"><a href="../coroutine/tcllib_coroutine.html">coroutine</a></b></dt> <dd><p>The name of the coroutine (if any) which implements this process.</p></dd> <dt><b class="cmd">frequency</b></dt> <dd><p>If -1, this process is terminated after the next event. If 0 this process should be called during every idle event. If positive, this process should generate events periodically. The frequency is an integer number of milliseconds between events.</p></dd> <dt><b class="cmd"><a href="../../../../index.html#object">object</a></b></dt> <dd><p>The object associated with this process or coroutine.</p></dd> <dt><b class="cmd">scheduled</b></dt> <dd><p>If non-zero, the absolute time from the epoch (in milliseconds) that this process will trigger an event. If zero, and the <b class="cmd">frequency</b> is also zero, this process is called every idle loop.</p></dd> <dt><b class="cmd"><a href="../../../../index.html#running">running</a></b></dt> <dd><p>A boolean flag. If true it indicates the process never returned or yielded during the event loop, and will not be called again until it does so.</p></dd> </dl></dd> <dt><a name="11"><b class="cmd">::cron::wake</b> <i class="arg">?who?</i></a></dt> <dd><p>Wake up cron, and arrange for its event loop to be run during the next Idle cycle.</p> <pre class="doctools_example"> ::cron::wake {I just did something important} </pre> </dd> </dl> <p>Several utility commands are provided that are used internally within cron and for testing cron, but may or may not be useful in the general cases.</p> <dl class="doctools_definitions"> <dt><a name="12"><b class="cmd">::cron::clock_step</b> <i class="arg">milliseconds</i></a></dt> <dd><p>Return a clock time absolute to the epoch which falls on the next border between one second and the next for the value of <i class="arg">milliseconds</i></p></dd> <dt><a name="13"><b class="cmd">::cron::clock_delay</b> <i class="arg">milliseconds</i></a></dt> <dd><p>Return a clock time absolute to the epoch which falls on the next border between one second and the next <i class="arg">milliseconds</i> in the future.</p></dd> <dt><a name="14"><b class="cmd">::cron::clock_sleep</b> <i class="arg">seconds</i> <i class="arg">?offset?</i></a></dt> <dd><p>Return a clock time absolute to the epoch which falls exactly <i class="arg">seconds</i> in the future. If offset is given it may be positive or negative, and will shift the final time to before or after the second would flip.</p></dd> <dt><a name="15"><b class="cmd">::cron::clock_set</b> <i class="arg">newtime</i></a></dt> <dd><p>Sets the internal clock for cron. This command will advance the time in 100ms increment, triggering events, until the internal time catches up with <i class="arg">newtime</i>.</p> <p><i class="arg">newtime</i> is expressed in absolute milliseconds since the beginning of the epoch.</p></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>odie</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/doctools/cvs.html.
︙ | ︙ | |||
166 167 168 169 170 171 172 | <dt>varname <i class="arg">fvar</i> (in)</dt> <dd><p>Has to refer to an array variable. Keys are strings containing date, author of a log entry, and a comment for that entry, in this order, separated by commas.</p> <p>The values are lists of the files the entry is touching.</p></dd> </dl></dd> <dt><a name="2"><b class="cmd">::doctools::cvs::toChangeLog</b> <i class="arg">evar</i> <i class="arg">cvar</i> <i class="arg">fvar</i></a></dt> | < | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | <dt>varname <i class="arg">fvar</i> (in)</dt> <dd><p>Has to refer to an array variable. Keys are strings containing date, author of a log entry, and a comment for that entry, in this order, separated by commas.</p> <p>The values are lists of the files the entry is touching.</p></dd> </dl></dd> <dt><a name="2"><b class="cmd">::doctools::cvs::toChangeLog</b> <i class="arg">evar</i> <i class="arg">cvar</i> <i class="arg">fvar</i></a></dt> <dd><p>The three arguments for this command are the same as the last three arguments of the command <b class="cmd">::doctools::cvs::scanLog</b>. This command however expects them to be filled with information about one or more logs. It takes this information and converts it into a text in the format of a ChangeLog as accepted and generated by <b class="syscmd"><a href="../../../../index.html#emacs">emacs</a></b>. The constructed text is returned as the result of the command.</p></dd> </dl> </div> |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/doctools/doctools_lang_intro.html.
︙ | ︙ | |||
216 217 218 219 220 221 222 | [<b class="cmd">require PACKAGE</b>] [description] [manpage_end] </pre> <p>Remember that the whitespace is optional. The document</p> <pre class="doctools_example"> [manpage_begin NAME SECTION VERSION] | < < < < < < < < < < | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | [<b class="cmd">require PACKAGE</b>] [description] [manpage_end] </pre> <p>Remember that the whitespace is optional. The document</p> <pre class="doctools_example"> [manpage_begin NAME SECTION VERSION] [copyright {YEAR AUTHOR}][titledesc TITLE][moddesc MODULE_TITLE] [require PACKAGE VERSION][require PACKAGE][description] [vset CATEGORY doctools] [include ../doctools2base/include/feedback.inc] [manpage_end] </pre> <p>has the same meaning as the example before.</p> |
︙ | ︙ | |||
420 421 422 423 424 425 426 | <p>The example demonstrating the use of text markup is an excerpt from the <i class="term"><a href="doctools_lang_cmdref.html">doctools language command reference</a></i>, with some highlighting added. It shows their use within a block of text, as the arguments of a list item command (<b class="cmd">call</b>), and our ability to nest them.</p> <pre class="doctools_example"> ... | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | <p>The example demonstrating the use of text markup is an excerpt from the <i class="term"><a href="doctools_lang_cmdref.html">doctools language command reference</a></i>, with some highlighting added. It shows their use within a block of text, as the arguments of a list item command (<b class="cmd">call</b>), and our ability to nest them.</p> <pre class="doctools_example"> ... [call [<b class="cmd">cmd arg_def</b>] [<b class="cmd">arg type</b>] [<b class="cmd">arg name</b>] [<b class="cmd">opt</b> [<b class="cmd">arg mode</b>]]] Text structure. List element. Argument list. Automatically closes the previous list element. Specifies the data-[<b class="cmd">arg type</b>] of the described argument of a command, its [<b class="cmd">arg name</b>] and its i/o-[<b class="cmd">arg mode</b>]. The latter is optional. ... </pre> </div> |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/fumagic/cfront.html.
︙ | ︙ | |||
137 138 139 140 141 142 143 | into recognizers based on the <b class="package"><a href="rtcore.html">fileutil::magic::rt</a></b> recognizer runtime package. For the generator backed used by this compiler see the package <b class="package"><a href="cgen.html">fileutil::magic::cgen</a></b>.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">COMMANDS</a></h2> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::fileutil::magic::cfront::compile</b> <i class="arg">path</i>...</a></dt> | | | | > > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | into recognizers based on the <b class="package"><a href="rtcore.html">fileutil::magic::rt</a></b> recognizer runtime package. For the generator backed used by this compiler see the package <b class="package"><a href="cgen.html">fileutil::magic::cgen</a></b>.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">COMMANDS</a></h2> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::fileutil::magic::cfront::compile</b> <i class="arg">path</i>...</a></dt> <dd><p>This command takes the paths of one or more files and directories and compiles all the files, and the files in all the directories into a single analyzer for all the file types specified in these files. It returns a list whose first item is a list per-file dictionaries of analyzer scripts and whose second item is a list of analyzer commands.</p> <p>All the files have to be in the format specified by magic(5).</p> <p>The result of the command is a Tcl script containing the generated recognizer.</p></dd> <dt><a name="2"><b class="cmd">::fileutil::magic::cfront::procdef</b> <i class="arg">procname</i> <i class="arg">path</i>...</a></dt> <dd><p>This command behaves like <b class="cmd">::fileutil::magic::cfront::compile</b> with regard to the specified path arguments, then wraps the resulting recognizer script into a procedure named <i class="arg">procname</i>, puts code |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/fumagic/rtcore.html.
︙ | ︙ | |||
121 122 123 124 125 126 127 | <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.5</b></li> <li>package require <b class="pkgname">fileutil::magic::rt <span class="opt">?2.0?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">::fileutil::magic::rt::></b></a></li> <li><a href="#2"><b class="cmd">::fileutil::magic::rt::<</b></a></li> | | | | | | | | < | < < < < | | | | < | < | | | | | | | | < | | | < < < < < | < < < < < < < < < < < < | > > > | | | < | < < | < < < < < < | | < > | | < | | | < < < < < | | < < < < < < < | < < < < < | | | < < < < | | | | < < < | | | | 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 | <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.5</b></li> <li>package require <b class="pkgname">fileutil::magic::rt <span class="opt">?2.0?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">::fileutil::magic::rt::></b></a></li> <li><a href="#2"><b class="cmd">::fileutil::magic::rt::<</b></a></li> <li><a href="#3"><b class="cmd">::fileutil::magic::rt::new</b> <i class="arg">chan</i> <i class="arg">named</i> <i class="arg">analyze</i></a></li> <li><a href="#4"><b class="cmd">::fileutil::magic::rt::file_start</b> <i class="arg">name</i></a></li> <li><a href="#5"><b class="cmd">::fileutil::magic::rt::emit</b> <i class="arg">msg</i></a></li> <li><a href="#6"><b class="cmd">::fileutil::magic::rt::O</b> <i class="arg">where</i></a></li> <li><a href="#7"><b class="cmd">::fileutil::magic::rt::R</b> <i class="arg">where</i></a></li> <li><a href="#8"><b class="cmd">::fileutil::magic::rt::Nv</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">compinvert</i> <i class="arg">comp</i> <i class="arg">expected</i></a></li> <li><a href="#9"><b class="cmd">::fileutil::magic::rt::N</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">testinvert</i> <i class="arg">compinvert</i> <i class="arg">mod</i> <i class="arg">mand</i> <i class="arg">comp</i> <i class="arg">expected</i></a></li> <li><a href="#10"><b class="cmd">::fileutil::magic::rt::S</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">testinvert</i> <i class="arg">mod</i> <i class="arg">mand</i> <i class="arg">comp</i> <i class="arg">val</i></a></li> <li><a href="#11"><b class="cmd">::fileutil::magic::rt::L</b> <i class="arg">newlevel</i></a></li> <li><a href="#12"><b class="cmd">::fileutil::magic::rt::I</b> <i class="arg">offset</i> <i class="arg">it</i> <i class="arg">ioi</i> <i class="arg">ioo</i> <i class="arg">iir</i> <i class="arg">io</i></a></li> <li><a href="#13"><b class="cmd">::fileutil::magic::rt::R</b> <i class="arg">offset</i></a></li> <li><a href="#14"><b class="cmd">::fileutil::magic::rt::U</b> <i class="arg">fileindex</i> <i class="arg">name</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This package provides the runtime core for file type recognition engines written in pure Tcl and is thus used by all other packages in this module such as <b class="package"><a href="filetypes.html">fileutil::magic::filetype</a></b> and the two compiler packages <b class="package"><a href="cgen.html">fileutil::magic::cgen</a></b> and <b class="package"><a href="cfront.html">fileutil::magic::cfront</a></b>.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">COMMANDS</a></h2> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::fileutil::magic::rt::></b></a></dt> <dd><p>Increment the level and perform related housekeeping</p></dd> <dt><a name="2"><b class="cmd">::fileutil::magic::rt::<</b></a></dt> <dd><p>Decrement the level and perform related housekeeping</p></dd> <dt><a name="3"><b class="cmd">::fileutil::magic::rt::new</b> <i class="arg">chan</i> <i class="arg">named</i> <i class="arg">analyze</i></a></dt> <dd><p>Create a new command which returns one description of the file each time it is called, and a code of <i class="arg">break</i> when there are no more descriptions. <i class="arg">chan</i> is the channel containing the data to describe. The channel configuration is then managed as needed. <i class="arg">named</i> is a dictionary of named tests, as generated by <b class="cmd">fileutil::magic::cfront::compile</b>. <i class="arg">test</i> is a command prefix for a routine composed of the list of commands as returned by <b class="cmd">fileutil::magic::cfront::compile</b>.</p></dd> <dt><a name="4"><b class="cmd">::fileutil::magic::rt::file_start</b> <i class="arg">name</i></a></dt> <dd><p>This command marks the start of a magic file when debugging. It returns the empty string as its result.</p></dd> <dt><a name="5"><b class="cmd">::fileutil::magic::rt::emit</b> <i class="arg">msg</i></a></dt> <dd><p>This command adds the text <i class="arg">msg</i> to the result buffer. The message may contain the following special character sequences. They will be replaced with buffered values before the message is added to the result. The command returns the empty string as its result.</p> <dl class="doctools_definitions"> <dt><b class="const">\b</b></dt> <dd><p>This sequence is removed</p></dd> <dt><b class="const">%s</b></dt> <dd><p>Replaced with the last buffered string value.</p></dd> <dt><b class="const">%ld</b></dt> <dd><p>Replaced with the last buffered numeric value.</p></dd> <dt><b class="const">%d</b></dt> <dd><p>See above.</p></dd> <dt><b class="const">${x:...?...}</b></dt> <dd><p>Substitute one string if the file is executable, and another string otherwise.</p></dd> </dl></dd> <dt><a name="6"><b class="cmd">::fileutil::magic::rt::O</b> <i class="arg">where</i></a></dt> <dd><p>Produce an offset from <i class="arg">where</i>, relative to the cursor one level up. Produce an offset from <i class="arg">where</i>, relative to the offset one level up.</p></dd> <dt><a name="8"><b class="cmd">::fileutil::magic::rt::Nv</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">compinvert</i> <i class="arg">comp</i> <i class="arg">expected</i></a></dt> <dd><p>A limited form of <b class="cmd">::fileutile::magic::rt::N</b> that only checks for equality and can't be told to invert the test.</p></dd> <dt><a name="9"><b class="cmd">::fileutil::magic::rt::N</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">testinvert</i> <i class="arg">compinvert</i> <i class="arg">mod</i> <i class="arg">mand</i> <i class="arg">comp</i> <i class="arg">expected</i></a></dt> <dd><p>Fetch the numeric value with <i class="arg">type</i> from the absolute location <i class="arg">offset</i>, compare it with <i class="arg">expected</i> using <i class="arg">comp</i> as the comparision operator, and returns the result.</p> <p>The argument <i class="arg">comp</i> must be one of Tcl's comparison operators.</p> <pre class="doctools_example"> <comp> <fetched-and-masked-value> <comp> <expected> </pre> <p>The special comparison operator <b class="const">x</b> signals that no comparison should be done, or, in other words, that the fetched value will always match <i class="arg">val</i>.</p></dd> <dt><a name="10"><b class="cmd">::fileutil::magic::rt::S</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">testinvert</i> <i class="arg">mod</i> <i class="arg">mand</i> <i class="arg">comp</i> <i class="arg">val</i></a></dt> <dd><p>Like <b class="cmd">::fileutil::magic::rt::N</b> except that it fetches and compares string types , not numeric data.</p></dd> <dt><a name="11"><b class="cmd">::fileutil::magic::rt::L</b> <i class="arg">newlevel</i></a></dt> <dd><p>Sets the current level in the calling context to <i class="arg">newlevel</i>. The command returns the empty string as its result.</p></dd> <dt><a name="12"><b class="cmd">::fileutil::magic::rt::I</b> <i class="arg">offset</i> <i class="arg">it</i> <i class="arg">ioi</i> <i class="arg">ioo</i> <i class="arg">iir</i> <i class="arg">io</i></a></dt> <dd><p>Calculates an offset based on an initial offset and the provided modifiers.</p></dd> <dt><a name="13"><b class="cmd">::fileutil::magic::rt::R</b> <i class="arg">offset</i></a></dt> <dd><p>Given an initial offset, calculates an offset relative to the cursor at the next level up. The cursor is the position in the data one character after the data extracted from the file one level up.</p></dd> <dt><a name="14"><b class="cmd">::fileutil::magic::rt::U</b> <i class="arg">fileindex</i> <i class="arg">name</i></a></dt> <dd><p>Add a level and use a named test script.</p></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">NUMERIC TYPES</a></h2> <dl class="doctools_definitions"> <dt><b class="const">byte</b></dt> <dd><p>8-bit integer</p></dd> <dt><b class="const">short</b></dt> |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/httpd/httpd.html.
1 |
| > | | | 1 2 3 4 5 6 7 8 9 10 11 | <!DOCTYPE html><html><head> <title>httpd - Tcl Web Server</title> <style type="text/css"><!-- HTML { background: #FFFFFF; color: black; } BODY { background: #FFFFFF; color: black; |
︙ | ︙ | |||
85 86 87 88 89 90 91 | margin-top: 1em; border-top: 1px solid black; } UL.doctools_requirements { margin-bottom: 1em; border-bottom: 1px solid black; } | | | | < > | < < < > | > | | | | > | | | | | | | | | | > > | > | | | | > > > | | | | | < < < | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | > > > > > > | | | | > | | > | | | > > | | | > > > > | | > > > > > > > | | | > > | | | | | > | > > > > > > > > > > > > > > | > | < < < > > | < < < | | | < | < < < < < < < < < < < | | | | | | < | | > | | | | | < < | | < < < < < < < < < < < < < < < | | > | | | | | | | > | | | | | > | | | < | | | > > > | > > > > > > > | < < | > | < < > > > > | > | | < < > > | | < > | | | | | | | < > | > | < > > > > > > > > > > > > < < < > | < | < > > > > | > > | > > > > > > > > > > | > | > > > > > | | > > > > > > > > | > > > > | > > > > > | | | | | < < | | < < < | < < < < < < < > < < | < < < < < < < < < < < < | < < > > > | < < > | < < < < < < < < < < < < < < < < < < < < < < > > | < | < | < < | < < | < < < < < < < < < < < < < < < < < < | | > > > > > > | | | | | | | > > > | | < | < > > > > > > > > > > > > > > > > | < < < < < < < < > > > > > | < > > > > | | < | | | > | < | > > | > > > > > > > > > > > > | > | < < < > | > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > | | < > > > > > | | | | > > | < > > > > > > > > > > > > > > | > | | < | > > > > > > > > | > > > | > > > > > > > > > > > > > > > > > > > | < < < > | | > > > > > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | > > > > > > > > | < | > > > > > > > | | > > > > > | > > | > > > | > > | > > | | | | | 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 | margin-top: 1em; border-top: 1px solid black; } UL.doctools_requirements { margin-bottom: 1em; border-bottom: 1px solid black; } --></style> </head> <!-- Generated from file 'httpd.man' by tcllib/doctools with format 'html' --> <!-- Copyright &copy; 2018 Sean Woods &lt;yoda@etoyoc.com&gt; --> <!-- httpd.n --> <body><div class="doctools"> <h1 class="doctools_title">httpd(n) 4.3 httpd "Tcl Web Server"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>httpd - A TclOO and coroutine based web server</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">Minimal Example</a></li> <li class="doctools_section"><a href="#section3">Classes</a> <ul> <li class="doctools_subsection"><a href="#subsection1">Class httpd::mime</a></li> <li class="doctools_subsection"><a href="#subsection2">Class httpd::reply</a></li> <li class="doctools_subsection"><a href="#subsection3">Class httpd::server</a></li> <li class="doctools_subsection"><a href="#subsection4">Class httpd::server::dispatch</a></li> <li class="doctools_subsection"><a href="#subsection5">Class httpd::content.redirect</a></li> <li class="doctools_subsection"><a href="#subsection6">Class httpd::content.cache</a></li> <li class="doctools_subsection"><a href="#subsection7">Class httpd::content.template</a></li> <li class="doctools_subsection"><a href="#subsection8">Class httpd::content.file</a></li> <li class="doctools_subsection"><a href="#subsection9">Class httpd::content.exec</a></li> <li class="doctools_subsection"><a href="#subsection10">Class httpd::content.proxy</a></li> <li class="doctools_subsection"><a href="#subsection11">Class httpd::content.cgi</a></li> <li class="doctools_subsection"><a href="#subsection12">Class httpd::protocol.scgi</a></li> <li class="doctools_subsection"><a href="#subsection13">Class httpd::content.scgi</a></li> <li class="doctools_subsection"><a href="#subsection14">Class httpd::server.scgi</a></li> <li class="doctools_subsection"><a href="#subsection15">Class httpd::content.websocket</a></li> <li class="doctools_subsection"><a href="#subsection16">Class httpd::plugin</a></li> <li class="doctools_subsection"><a href="#subsection17">Class httpd::plugin.dict_dispatch</a></li> <li class="doctools_subsection"><a href="#subsection18">Class httpd::reply.memchan</a></li> <li class="doctools_subsection"><a href="#subsection19">Class httpd::plugin.local_memchan</a></li> </ul> </li> <li class="doctools_section"><a href="#section4">AUTHORS</a></li> <li class="doctools_section"><a href="#section5">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.6</b></li> <li>package require <b class="pkgname">httpd <span class="opt">?4.3?</span></b></li> <li>package require <b class="pkgname">uuid</b></li> <li>package require <b class="pkgname">clay</b></li> <li>package require <b class="pkgname">coroutine</b></li> <li>package require <b class="pkgname">fileutil</b></li> <li>package require <b class="pkgname">fileutil::magic::filetype</b></li> <li>package require <b class="pkgname">websocket</b></li> <li>package require <b class="pkgname">mime</b></li> <li>package require <b class="pkgname">cron</b></li> <li>package require <b class="pkgname">uri</b></li> <li>package require <b class="pkgname">Markdown</b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1">method <b class="cmd">ChannelCopy</b> <i class="arg">in</i> <i class="arg">out</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#2">method <b class="cmd">html_header</b> <span class="opt">?<i class="arg">title</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#3">method <b class="cmd">html_footer</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#4">method <b class="cmd">http_code_string</b> <i class="arg">code</i></a></li> <li><a href="#5">method <b class="cmd">HttpHeaders</b> <i class="arg">sock</i> <span class="opt">?<i class="arg">debug</i> <b class="const"></b>?</span></a></li> <li><a href="#6">method <b class="cmd">HttpHeaders_Default</b></a></li> <li><a href="#7">method <b class="cmd">HttpServerHeaders</b></a></li> <li><a href="#8">method <b class="cmd">MimeParse</b> <i class="arg">mimetext</i></a></li> <li><a href="#9">method <b class="cmd">Url_Decode</b> <i class="arg">data</i></a></li> <li><a href="#10">method <b class="cmd">Url_PathCheck</b> <i class="arg">urlsuffix</i></a></li> <li><a href="#11">method <b class="cmd">wait</b> <i class="arg">mode</i> <i class="arg">sock</i></a></li> <li><a href="#12">method <b class="cmd">constructor</b> <i class="arg">ServerObj</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#13">method <b class="cmd">destructor</b> <span class="opt">?<i class="arg">dictargs</i>?</span></a></li> <li><a href="#14">method <b class="cmd">close</b></a></li> <li><a href="#15">method <b class="cmd">Log_Dispatched</b></a></li> <li><a href="#16">method <b class="cmd">dispatch</b> <i class="arg">newsock</i> <i class="arg">datastate</i></a></li> <li><a href="#17">method <b class="cmd">Dispatch</b></a></li> <li><a href="#18">method <b class="cmd">html_css</b></a></li> <li><a href="#19">method <b class="cmd">html_header</b> <i class="arg">title</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#20">method <b class="cmd">html_footer</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#21">method <b class="cmd">error</b> <i class="arg">code</i> <span class="opt">?<i class="arg">msg</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">errorInfo</i> <b class="const"></b>?</span></a></li> <li><a href="#22">method <b class="cmd">content</b></a></li> <li><a href="#23">method <b class="cmd">EncodeStatus</b> <i class="arg">status</i></a></li> <li><a href="#24">method <b class="cmd">log</b> <i class="arg">type</i> <span class="opt">?<i class="arg">info</i> <b class="const"></b>?</span></a></li> <li><a href="#25">method <b class="cmd">CoroName</b></a></li> <li><a href="#26">method <b class="cmd">DoOutput</b></a></li> <li><a href="#27">method <b class="cmd">FormData</b></a></li> <li><a href="#28">method <b class="cmd">PostData</b> <i class="arg">length</i></a></li> <li><a href="#29">method <b class="cmd">Session_Load</b></a></li> <li><a href="#30">method <b class="cmd">TransferComplete</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#31">method <b class="cmd">puts</b> <i class="arg">line</i></a></li> <li><a href="#32">method <b class="cmd">RequestFind</b> <i class="arg">field</i></a></li> <li><a href="#33">method <b class="cmd">request</b> <i class="arg">subcommand</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#34">method <b class="cmd">reply</b> <i class="arg">subcommand</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#35">method <b class="cmd">reset</b></a></li> <li><a href="#36">method <b class="cmd">timeOutCheck</b></a></li> <li><a href="#37">method <b class="cmd">timestamp</b></a></li> <li><a href="#38">method <b class="cmd">constructor</b> <i class="arg">args</i> <span class="opt">?<i class="arg">port</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">myaddr</i> <b class="const">127.0.0.1</b>?</span> <span class="opt">?<i class="arg">string</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">name</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">doc_root</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">reverse_dns</i> <b class="const">0</b>?</span> <span class="opt">?<i class="arg">configuration_file</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">protocol</i> <b class="const">HTTP/1.1</b>?</span></a></li> <li><a href="#39">method <b class="cmd">destructor</b> <span class="opt">?<i class="arg">dictargs</i>?</span></a></li> <li><a href="#40">method <b class="cmd">connect</b> <i class="arg">sock</i> <i class="arg">ip</i> <i class="arg">port</i></a></li> <li><a href="#41">method <b class="cmd">ServerHeaders</b> <i class="arg">ip</i> <i class="arg">http_request</i> <i class="arg">mimetxt</i></a></li> <li><a href="#42">method <b class="cmd">Connect</b> <i class="arg">uuid</i> <i class="arg">sock</i> <i class="arg">ip</i></a></li> <li><a href="#43">method <b class="cmd">counter</b> <i class="arg">which</i></a></li> <li><a href="#44">method <b class="cmd">CheckTimeout</b></a></li> <li><a href="#45">method <b class="cmd">debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#46">method <b class="cmd">dispatch</b> <i class="arg">data</i></a></li> <li><a href="#47">method <b class="cmd">Dispatch_Default</b> <i class="arg">reply</i></a></li> <li><a href="#48">method <b class="cmd">Dispatch_Local</b> <i class="arg">data</i></a></li> <li><a href="#49">method <b class="cmd">Headers_Local</b> <i class="arg">varname</i></a></li> <li><a href="#50">method <b class="cmd">Headers_Process</b> <i class="arg">varname</i></a></li> <li><a href="#51">method <b class="cmd">HostName</b> <i class="arg">ipaddr</i></a></li> <li><a href="#52">method <b class="cmd">log</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#53">method <b class="cmd">plugin</b> <i class="arg">slot</i> <span class="opt">?<i class="arg">class</i> <b class="const"></b>?</span></a></li> <li><a href="#54">method <b class="cmd">port_listening</b></a></li> <li><a href="#55">method <b class="cmd">PrefixNormalize</b> <i class="arg">prefix</i></a></li> <li><a href="#56">method <b class="cmd">source</b> <i class="arg">filename</i></a></li> <li><a href="#57">method <b class="cmd">start</b></a></li> <li><a href="#58">method <b class="cmd">stop</b></a></li> <li><a href="#59">method <b class="cmd">SubObject {} db</b></a></li> <li><a href="#60">method <b class="cmd">SubObject {} default</b></a></li> <li><a href="#61">method <b class="cmd">template</b> <i class="arg">page</i></a></li> <li><a href="#62">method <b class="cmd">TemplateSearch</b> <i class="arg">page</i></a></li> <li><a href="#63">method <b class="cmd">Thread_start</b></a></li> <li><a href="#64">method <b class="cmd">Uuid_Generate</b></a></li> <li><a href="#65">method <b class="cmd">Validate_Connection</b> <i class="arg">sock</i> <i class="arg">ip</i></a></li> <li><a href="#66">method <b class="cmd">reset</b></a></li> <li><a href="#67">method <b class="cmd">content</b></a></li> <li><a href="#68">method <b class="cmd">Dispatch</b></a></li> <li><a href="#69">method <b class="cmd">content</b></a></li> <li><a href="#70">method <b class="cmd">FileName</b></a></li> <li><a href="#71">method <b class="cmd">DirectoryListing</b> <i class="arg">local_file</i></a></li> <li><a href="#72">method <b class="cmd">content</b></a></li> <li><a href="#73">method <b class="cmd">Dispatch</b></a></li> <li><a href="#74">method <b class="cmd">CgiExec</b> <i class="arg">execname</i> <i class="arg">script</i> <i class="arg">arglist</i></a></li> <li><a href="#75">method <b class="cmd">Cgi_Executable</b> <i class="arg">script</i></a></li> <li><a href="#76">method <b class="cmd">proxy_channel</b></a></li> <li><a href="#77">method <b class="cmd">proxy_path</b></a></li> <li><a href="#78">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></li> <li><a href="#79">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#80">method <b class="cmd">Dispatch</b></a></li> <li><a href="#81">method <b class="cmd">FileName</b></a></li> <li><a href="#82">method <b class="cmd">proxy_channel</b></a></li> <li><a href="#83">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></li> <li><a href="#84">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#85">method <b class="cmd">DirectoryListing</b> <i class="arg">local_file</i></a></li> <li><a href="#86">method <b class="cmd">EncodeStatus</b> <i class="arg">status</i></a></li> <li><a href="#87">method <b class="cmd">scgi_info</b></a></li> <li><a href="#88">method <b class="cmd">proxy_channel</b></a></li> <li><a href="#89">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></li> <li><a href="#90">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#91">method <b class="cmd">debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#92">method <b class="cmd">Connect</b> <i class="arg">uuid</i> <i class="arg">sock</i> <i class="arg">ip</i></a></li> <li><a href="#93">method <b class="cmd">Dispatch_Dict</b> <i class="arg">data</i></a></li> <li><a href="#94">method <b class="cmd">uri {} add</b> <i class="arg">vhosts</i> <i class="arg">patterns</i> <i class="arg">info</i></a></li> <li><a href="#95">method <b class="cmd">uri {} direct</b> <i class="arg">vhosts</i> <i class="arg">patterns</i> <i class="arg">info</i> <i class="arg">body</i></a></li> <li><a href="#96">method <b class="cmd">output</b></a></li> <li><a href="#97">method <b class="cmd">DoOutput</b></a></li> <li><a href="#98">method <b class="cmd">close</b></a></li> <li><a href="#99">method <b class="cmd">local_memchan</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#100">method <b class="cmd">Connect_Local</b> <i class="arg">uuid</i> <i class="arg">sock</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This module implements a web server, suitable for embedding in an application. The server is object oriented, and contains all of the fundamentals needed for a full service website.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">Minimal Example</a></h2> <p>Starting a web service requires starting a class of type <b class="cmd">httpd::server</b>, and providing that server with one or more URIs to service, and <b class="cmd">httpd::reply</b> derived classes to generate them.</p> <pre class="doctools_example"> oo::class create ::reply.hello { method content {} { my puts "<HTML><HEAD><TITLE>IRM Dispatch Server</TITLE></HEAD><BODY>" my puts "<h1>Hello World!</h1>" my puts </BODY></HTML> } } ::httpd::server create HTTPD port 8015 myaddr 127.0.0.1 doc_root ~/htdocs HTTPD plugin dispatch httpd::server::dispatch HTTPD uri add * /hello [list mixin reply.hello] </pre> <p>The bare module does have facilities to hose a files from a file system. Files that end in a .tml will be substituted in the style of Tclhttpd:</p> <pre class="doctools_example"> <!-- hello.tml --> [my html_header {Hello World!}] Your Server is running. <p> The time is now [clock format [clock seconds]] [my html_footer] </pre> <p>A complete example of an httpd server is in the /examples directory of Tcllib. It also show how to dispatch URIs to other processes via SCGI and HTTP proxies.</p> <pre class="doctools_example"> cd ~/tcl/sandbox/tcllib tclsh examples/httpd.tcl </pre> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Classes</a></h2> <div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Class httpd::mime</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="1">method <b class="cmd">ChannelCopy</b> <i class="arg">in</i> <i class="arg">out</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="2">method <b class="cmd">html_header</b> <span class="opt">?<i class="arg">title</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="3">method <b class="cmd">html_footer</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="4">method <b class="cmd">http_code_string</b> <i class="arg">code</i></a></dt> <dd></dd> <dt><a name="5">method <b class="cmd">HttpHeaders</b> <i class="arg">sock</i> <span class="opt">?<i class="arg">debug</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="6">method <b class="cmd">HttpHeaders_Default</b></a></dt> <dd></dd> <dt><a name="7">method <b class="cmd">HttpServerHeaders</b></a></dt> <dd></dd> <dt><a name="8">method <b class="cmd">MimeParse</b> <i class="arg">mimetext</i></a></dt> <dd><p>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 <b class="cmd">error</b> method, and immediately invoke the <b class="cmd">output</b> method to produce an error code and close the connection.</p></dd> <dt><a name="9">method <b class="cmd">Url_Decode</b> <i class="arg">data</i></a></dt> <dd><p>De-httpizes a string.</p></dd> <dt><a name="10">method <b class="cmd">Url_PathCheck</b> <i class="arg">urlsuffix</i></a></dt> <dd></dd> <dt><a name="11">method <b class="cmd">wait</b> <i class="arg">mode</i> <i class="arg">sock</i></a></dt> <dd></dd> </dl> </div> <div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">Class httpd::reply</a></h3> <p><em>ancestors</em>: <b class="class">httpd::mime</b></p> <p>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 <i class="arg">chan</i> variable. The process of generating a reply begins with an <b class="cmd">httpd::server</b> generating a <b class="cmd">http::class</b> object, mixing in a set of behaviors and then invoking the reply object's <b class="cmd">dispatch</b> method. In normal operations the <b class="cmd">dispatch</b> method:</p> <ol class="doctools_enumerated"> <li><p>Invokes the <b class="cmd">reset</b> method for the object to populate default headers.</p></li> <li><p>Invokes the <b class="cmd">HttpHeaders</b> method to stream the MIME headers out of the socket</p></li> <li><p>Invokes the <b class="cmd">request parse</b> method to convert the stream of MIME headers into a dict that can be read via the <b class="cmd">request</b> method.</p></li> <li><p>Stores the raw stream of MIME headers in the <i class="arg">rawrequest</i> variable of the object.</p></li> <li><p>Invokes the <b class="cmd">content</b> method for the object, generating an call to the <b class="cmd">error</b> method if an exception is raised.</p></li> <li><p>Invokes the <b class="cmd">output</b> method for the object</p></li> </ol> <p>Developers have the option of streaming output to a buffer via the <b class="cmd">puts</b> method of the reply, or simply populating the <i class="arg">reply_body</i> variable of the object. The information returned by the <b class="cmd">content</b> method is not interpreted in any way. If an exception is thrown (via the <b class="cmd">error</b> command in Tcl, for example) the caller will auto-generate a 500 {Internal Error} message. A typical implementation of <b class="cmd">content</b> look like:</p> <pre class="doctools_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] } } </pre> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="12">method <b class="cmd">constructor</b> <i class="arg">ServerObj</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="13">method <b class="cmd">destructor</b> <span class="opt">?<i class="arg">dictargs</i>?</span></a></dt> <dd><p>clean up on exit</p></dd> <dt><a name="14">method <b class="cmd">close</b></a></dt> <dd><p>Close channels opened by this object</p></dd> <dt><a name="15">method <b class="cmd">Log_Dispatched</b></a></dt> <dd><p>Record a dispatch event</p></dd> <dt><a name="16">method <b class="cmd">dispatch</b> <i class="arg">newsock</i> <i class="arg">datastate</i></a></dt> <dd><p>Accept the handoff from the server object of the socket <em>newsock</em> and feed it the state <em>datastate</em>. Fields the <em>datastate</em> are looking for in particular are:</p> <p>* <b class="const">mixin</b> - A key/value list of slots and classes to be mixed into the object prior to invoking <b class="cmd">Dispatch</b>.</p> <p>* <b class="const">http</b> - A key/value list of values to populate the object's <em>request</em> ensemble</p> <p>All other fields are passed along to the <b class="method">clay</b> structure of the object.</p></dd> <dt><a name="17">method <b class="cmd">Dispatch</b></a></dt> <dd></dd> <dt><a name="18">method <b class="cmd">html_css</b></a></dt> <dd></dd> <dt><a name="19">method <b class="cmd">html_header</b> <i class="arg">title</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="20">method <b class="cmd">html_footer</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="21">method <b class="cmd">error</b> <i class="arg">code</i> <span class="opt">?<i class="arg">msg</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">errorInfo</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="22">method <b class="cmd">content</b></a></dt> <dd><p>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"</p></dd> <dt><a name="23">method <b class="cmd">EncodeStatus</b> <i class="arg">status</i></a></dt> <dd><p>Formulate a standard HTTP status header from he string provided.</p></dd> <dt><a name="24">method <b class="cmd">log</b> <i class="arg">type</i> <span class="opt">?<i class="arg">info</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="25">method <b class="cmd">CoroName</b></a></dt> <dd></dd> <dt><a name="26">method <b class="cmd">DoOutput</b></a></dt> <dd><p>Generates the the HTTP reply, streams that reply back across <i class="arg">chan</i>, and destroys the object.</p></dd> <dt><a name="27">method <b class="cmd">FormData</b></a></dt> <dd><p>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 <b class="cmd">mime</b> package, including the MIME_TOKEN, which can be fed back into the mime package to read out the contents.</p></dd> <dt><a name="28">method <b class="cmd">PostData</b> <i class="arg">length</i></a></dt> <dd><p>Stream <i class="arg">length</i> bytes from the <i class="arg">chan</i> socket, but only of the request is a POST or PUSH. Returns an empty string otherwise.</p></dd> <dt><a name="29">method <b class="cmd">Session_Load</b></a></dt> <dd><p>Manage session data</p></dd> <dt><a name="30">method <b class="cmd">TransferComplete</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Intended to be invoked from <b class="cmd">chan copy</b> as a callback. This closes every channel fed to it on the command line, and then destroys the object.</p> <pre class="doctools_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 </pre> </dd> <dt><a name="31">method <b class="cmd">puts</b> <i class="arg">line</i></a></dt> <dd><p>Appends the value of <i class="arg">string</i> to the end of <i class="arg">reply_body</i>, as well as a trailing newline character.</p></dd> <dt><a name="32">method <b class="cmd">RequestFind</b> <i class="arg">field</i></a></dt> <dd></dd> <dt><a name="33">method <b class="cmd">request</b> <i class="arg">subcommand</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="34">method <b class="cmd">reply</b> <i class="arg">subcommand</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="35">method <b class="cmd">reset</b></a></dt> <dd><p>Clear the contents of the <i class="arg">reply_body</i> variable, and reset all headers in the <b class="cmd">reply</b> structure back to the defaults for this object.</p></dd> <dt><a name="36">method <b class="cmd">timeOutCheck</b></a></dt> <dd><p>Called from the <b class="cmd">http::server</b> 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 <i class="arg">chan</i> socket.</p></dd> <dt><a name="37">method <b class="cmd">timestamp</b></a></dt> <dd><p>Return the current system time in the format:</p> <pre class="doctools_example">%a, %d %b %Y %T %Z</pre> </dd> </dl> </div> <div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Class httpd::server</a></h3> <p><em>ancestors</em>: <b class="class">httpd::mime</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="38">method <b class="cmd">constructor</b> <i class="arg">args</i> <span class="opt">?<i class="arg">port</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">myaddr</i> <b class="const">127.0.0.1</b>?</span> <span class="opt">?<i class="arg">string</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">name</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">doc_root</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">reverse_dns</i> <b class="const">0</b>?</span> <span class="opt">?<i class="arg">configuration_file</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">protocol</i> <b class="const">HTTP/1.1</b>?</span></a></dt> <dd></dd> <dt><a name="39">method <b class="cmd">destructor</b> <span class="opt">?<i class="arg">dictargs</i>?</span></a></dt> <dd></dd> <dt><a name="40">method <b class="cmd">connect</b> <i class="arg">sock</i> <i class="arg">ip</i> <i class="arg">port</i></a></dt> <dd><p>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 <b class="cmd">Connect</b> method.</p></dd> <dt><a name="41">method <b class="cmd">ServerHeaders</b> <i class="arg">ip</i> <i class="arg">http_request</i> <i class="arg">mimetxt</i></a></dt> <dd></dd> <dt><a name="42">method <b class="cmd">Connect</b> <i class="arg">uuid</i> <i class="arg">sock</i> <i class="arg">ip</i></a></dt> <dd><p>This method reads HTTP headers, and then consults the <b class="cmd">dispatch</b> method to determine if the request is valid, and/or what kind of reply to generate. Under normal cases, an object of class <b class="cmd">::http::reply</b> is created, and that class's <b class="cmd">dispatch</b> 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.</p></dd> <dt><a name="43">method <b class="cmd">counter</b> <i class="arg">which</i></a></dt> <dd><p>Increment an internal counter.</p></dd> <dt><a name="44">method <b class="cmd">CheckTimeout</b></a></dt> <dd><p>Check open connections for a time out event.</p></dd> <dt><a name="45">method <b class="cmd">debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="46">method <b class="cmd">dispatch</b> <i class="arg">data</i></a></dt> <dd><p>Given a key/value list of information, return a data structure describing how the server should reply.</p></dd> <dt><a name="47">method <b class="cmd">Dispatch_Default</b> <i class="arg">reply</i></a></dt> <dd><p>Method dispatch method of last resort before returning a 404 NOT FOUND error. The default behavior is to look for a file in <em>DOCUMENT_ROOT</em> which matches the query.</p></dd> <dt><a name="48">method <b class="cmd">Dispatch_Local</b> <i class="arg">data</i></a></dt> <dd><p>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.</p></dd> <dt><a name="49">method <b class="cmd">Headers_Local</b> <i class="arg">varname</i></a></dt> <dd><p>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.</p></dd> <dt><a name="50">method <b class="cmd">Headers_Process</b> <i class="arg">varname</i></a></dt> <dd><p>Introspect and possibly modify a data structure destined for a reply. This method is built dynamically by the <b class="cmd">plugin</b> method.</p></dd> <dt><a name="51">method <b class="cmd">HostName</b> <i class="arg">ipaddr</i></a></dt> <dd><p>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 <em>dns</em> module from tcllib.</p></dd> <dt><a name="52">method <b class="cmd">log</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>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.</p></dd> <dt><a name="53">method <b class="cmd">plugin</b> <i class="arg">slot</i> <span class="opt">?<i class="arg">class</i> <b class="const"></b>?</span></a></dt> <dd><p>Incorporate behaviors from a plugin. This method dynamically rebuilds the <b class="cmd">Dispatch</b> and <b class="cmd">Headers</b> method. For every plugin, the server looks for the following entries in <em>clay plugin/</em>:</p> <p><em>load</em> - A script to invoke in the server's namespace during the <b class="cmd">plugin</b> method invokation.</p> <p><em>dispatch</em> - A script to stitch into the server's <b class="cmd">Dispatch</b> method.</p> <p><em>headers</em> - A script to stitch into the server's <b class="cmd">Headers</b> method.</p> <p><em>thread</em> - A script to stitch into the server's <b class="cmd">Thread_start</b> method.</p></dd> <dt><a name="54">method <b class="cmd">port_listening</b></a></dt> <dd><p>Return the actual port that httpd is listening on.</p></dd> <dt><a name="55">method <b class="cmd">PrefixNormalize</b> <i class="arg">prefix</i></a></dt> <dd><p>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.</p></dd> <dt><a name="56">method <b class="cmd">source</b> <i class="arg">filename</i></a></dt> <dd></dd> <dt><a name="57">method <b class="cmd">start</b></a></dt> <dd><p>Open the socket listener.</p></dd> <dt><a name="58">method <b class="cmd">stop</b></a></dt> <dd><p>Shut off the socket listener, and destroy any pending replies.</p></dd> <dt><a name="59">method <b class="cmd">SubObject {} db</b></a></dt> <dd></dd> <dt><a name="60">method <b class="cmd">SubObject {} default</b></a></dt> <dd></dd> <dt><a name="61">method <b class="cmd">template</b> <i class="arg">page</i></a></dt> <dd><p>Return a template for the string <i class="arg">page</i></p></dd> <dt><a name="62">method <b class="cmd">TemplateSearch</b> <i class="arg">page</i></a></dt> <dd><p>Perform a search for the template that best matches <i class="arg">page</i>. 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 <span class="opt">?doc_root?</span> directory.</p></dd> <dt><a name="63">method <b class="cmd">Thread_start</b></a></dt> <dd><p>Built by the <b class="cmd">plugin</b> method. Called by the <b class="cmd">start</b> method. Intended to allow plugins to spawn worker threads.</p></dd> <dt><a name="64">method <b class="cmd">Uuid_Generate</b></a></dt> <dd><p>Generate a GUUID. Used to ensure every request has a unique ID. The default implementation is:</p> <pre class="doctools_example"> return [::uuid::uuid generate] </pre> </dd> <dt><a name="65">method <b class="cmd">Validate_Connection</b> <i class="arg">sock</i> <i class="arg">ip</i></a></dt> <dd><p>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.</p></dd> </dl> </div> <div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Class httpd::server::dispatch</a></h3> <p><em>ancestors</em>: <b class="class">httpd::server</b></p> <p>Provide a backward compadible alias</p> </div> <div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Class httpd::content.redirect</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="66">method <b class="cmd">reset</b></a></dt> <dd></dd> <dt><a name="67">method <b class="cmd">content</b></a></dt> <dd></dd> </dl> </div> <div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Class httpd::content.cache</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="68">method <b class="cmd">Dispatch</b></a></dt> <dd></dd> </dl> </div> <div id="subsection7" class="doctools_subsection"><h3><a name="subsection7">Class httpd::content.template</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="69">method <b class="cmd">content</b></a></dt> <dd></dd> </dl> </div> <div id="subsection8" class="doctools_subsection"><h3><a name="subsection8">Class httpd::content.file</a></h3> <p>Class to deliver Static content When utilized, this class is fed a local filename by the dispatcher</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="70">method <b class="cmd">FileName</b></a></dt> <dd></dd> <dt><a name="71">method <b class="cmd">DirectoryListing</b> <i class="arg">local_file</i></a></dt> <dd></dd> <dt><a name="72">method <b class="cmd">content</b></a></dt> <dd></dd> <dt><a name="73">method <b class="cmd">Dispatch</b></a></dt> <dd></dd> </dl> </div> <div id="subsection9" class="doctools_subsection"><h3><a name="subsection9">Class httpd::content.exec</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="74">method <b class="cmd">CgiExec</b> <i class="arg">execname</i> <i class="arg">script</i> <i class="arg">arglist</i></a></dt> <dd></dd> <dt><a name="75">method <b class="cmd">Cgi_Executable</b> <i class="arg">script</i></a></dt> <dd></dd> </dl> </div> <div id="subsection10" class="doctools_subsection"><h3><a name="subsection10">Class httpd::content.proxy</a></h3> <p><em>ancestors</em>: <b class="class">httpd::content.exec</b></p> <p>Return data from an proxy process</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="76">method <b class="cmd">proxy_channel</b></a></dt> <dd></dd> <dt><a name="77">method <b class="cmd">proxy_path</b></a></dt> <dd></dd> <dt><a name="78">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></dt> <dd></dd> <dt><a name="79">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="80">method <b class="cmd">Dispatch</b></a></dt> <dd></dd> </dl> </div> <div id="subsection11" class="doctools_subsection"><h3><a name="subsection11">Class httpd::content.cgi</a></h3> <p><em>ancestors</em>: <b class="class">httpd::content.proxy</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="81">method <b class="cmd">FileName</b></a></dt> <dd></dd> <dt><a name="82">method <b class="cmd">proxy_channel</b></a></dt> <dd></dd> <dt><a name="83">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></dt> <dd></dd> <dt><a name="84">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="85">method <b class="cmd">DirectoryListing</b> <i class="arg">local_file</i></a></dt> <dd><p>For most CGI applications a directory list is vorboten</p></dd> </dl> </div> <div id="subsection12" class="doctools_subsection"><h3><a name="subsection12">Class httpd::protocol.scgi</a></h3> <p>Return data from an SCGI process</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="86">method <b class="cmd">EncodeStatus</b> <i class="arg">status</i></a></dt> <dd></dd> </dl> </div> <div id="subsection13" class="doctools_subsection"><h3><a name="subsection13">Class httpd::content.scgi</a></h3> <p><em>ancestors</em>: <b class="class">httpd::content.proxy</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="87">method <b class="cmd">scgi_info</b></a></dt> <dd></dd> <dt><a name="88">method <b class="cmd">proxy_channel</b></a></dt> <dd></dd> <dt><a name="89">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></dt> <dd></dd> <dt><a name="90">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection14" class="doctools_subsection"><h3><a name="subsection14">Class httpd::server.scgi</a></h3> <p><em>ancestors</em>: <b class="class">httpd::server</b></p> <p>Act as an SCGI Server</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="91">method <b class="cmd">debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="92">method <b class="cmd">Connect</b> <i class="arg">uuid</i> <i class="arg">sock</i> <i class="arg">ip</i></a></dt> <dd></dd> </dl> </div> <div id="subsection15" class="doctools_subsection"><h3><a name="subsection15">Class httpd::content.websocket</a></h3> <p>Upgrade a connection to a websocket</p> </div> <div id="subsection16" class="doctools_subsection"><h3><a name="subsection16">Class httpd::plugin</a></h3> <p>httpd plugin template</p> </div> <div id="subsection17" class="doctools_subsection"><h3><a name="subsection17">Class httpd::plugin.dict_dispatch</a></h3> <p>A rudimentary plugin that dispatches URLs from a dict data structure</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="93">method <b class="cmd">Dispatch_Dict</b> <i class="arg">data</i></a></dt> <dd><p>Implementation of the dispatcher</p></dd> <dt><a name="94">method <b class="cmd">uri {} add</b> <i class="arg">vhosts</i> <i class="arg">patterns</i> <i class="arg">info</i></a></dt> <dd></dd> <dt><a name="95">method <b class="cmd">uri {} direct</b> <i class="arg">vhosts</i> <i class="arg">patterns</i> <i class="arg">info</i> <i class="arg">body</i></a></dt> <dd></dd> </dl> </div> <div id="subsection18" class="doctools_subsection"><h3><a name="subsection18">Class httpd::reply.memchan</a></h3> <p><em>ancestors</em>: <b class="class">httpd::reply</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="96">method <b class="cmd">output</b></a></dt> <dd></dd> <dt><a name="97">method <b class="cmd">DoOutput</b></a></dt> <dd></dd> <dt><a name="98">method <b class="cmd">close</b></a></dt> <dd></dd> </dl> </div> <div id="subsection19" class="doctools_subsection"><h3><a name="subsection19">Class httpd::plugin.local_memchan</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="99">method <b class="cmd">local_memchan</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="100">method <b class="cmd">Connect_Local</b> <i class="arg">uuid</i> <i class="arg">sock</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>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</p></dd> </dl> </div> </div> <div id="section4" class="doctools_section"><h2><a name="section4">AUTHORS</a></h2> <p>Sean Woods</p> </div> <div id="section5" class="doctools_section"><h2><a name="section5">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>network</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. Please also report any ideas for enhancements you may have for either package and/or documentation.</p> <p>When proposing code changes, please provide <em>unified diffs</em>, i.e the output of <b class="const">diff -u</b>.</p> <p>Note further that <em>attachments</em> are strongly preferred over inlined patches. Attachments can be made by going to the <b class="const">Edit</b> form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p>TclOO, WWW, http, httpd, httpserver, services</p> </div> <div id="category" class="doctools_section"><h2><a name="category">Category</a></h2> <p>Networking</p> </div> <div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> <p>Copyright © 2018 Sean Woods <[email protected]></p> </div> </div></body></html> |
Changes to embedded/www/tcllib/files/modules/log/log.html.
︙ | ︙ | |||
224 225 226 227 228 229 230 | <dd><p>Compares two levels (including unique abbreviations) with respect to their priority. This command can be used by the -command option of lsort. The result is one of -1, 0 or 1 or an error. A result of -1 signals that level1 is of less priority than level2. 0 signals that both levels have the same priority. 1 signals that level1 has higher priority than level2.</p></dd> <dt><a name="8"><b class="cmd">::log::lvSuppress</b> <i class="arg">level</i> {<i class="arg">suppress</i> 1}</a></dt> | < | < | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | <dd><p>Compares two levels (including unique abbreviations) with respect to their priority. This command can be used by the -command option of lsort. The result is one of -1, 0 or 1 or an error. A result of -1 signals that level1 is of less priority than level2. 0 signals that both levels have the same priority. 1 signals that level1 has higher priority than level2.</p></dd> <dt><a name="8"><b class="cmd">::log::lvSuppress</b> <i class="arg">level</i> {<i class="arg">suppress</i> 1}</a></dt> <dd><p>(Un)suppresses the output of messages having the specified level. Unique abbreviations for the level are allowed here too.</p></dd> <dt><a name="9"><b class="cmd">::log::lvSuppressLE</b> <i class="arg">level</i> {<i class="arg">suppress</i> 1}</a></dt> <dd><p>(Un)suppresses the output of messages having the specified level or one of lesser priority. Unique abbreviations for the level are allowed here too.</p></dd> <dt><a name="10"><b class="cmd">::log::lvIsSuppressed</b> <i class="arg">level</i></a></dt> <dd><p>Asks the package whether the specified level is currently suppressed. Unique abbreviations of level names are allowed.</p></dd> <dt><a name="11"><b class="cmd">::log::lvCmd</b> <i class="arg">level</i> <i class="arg">cmd</i></a></dt> <dd><p>Defines for the specified level with which command to write the |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/math/math_geometry.html.
︙ | ︙ | |||
198 199 200 201 202 203 204 | <li><p><em>polyline</em> - a list of an even number of coordinates, interpreted as the x- and y-coordinates of an ordered set of points.</p></li> <li><p><em>polygon</em> - like a polyline, but the implicit assumption is that the polyline is closed (if the first and last points do not coincide, the missing segment is automatically added).</p></li> <li><p><em>point set</em> - again a list of an even number of coordinates, but the points are regarded without any ordering.</p></li> | | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | <li><p><em>polyline</em> - a list of an even number of coordinates, interpreted as the x- and y-coordinates of an ordered set of points.</p></li> <li><p><em>polygon</em> - like a polyline, but the implicit assumption is that the polyline is closed (if the first and last points do not coincide, the missing segment is automatically added).</p></li> <li><p><em>point set</em> - again a list of an even number of coordinates, but the points are regarded without any ordering.</p></li> <li><p><em>circle</em> - a list of three numbers, the first two are the coordinates of the centre and the third is the radius.</p></li> </ul> </div> <div id="section2" class="doctools_section"><h2><a name="section2">PROCEDURES</a></h2> <p>The package defines the following public procedures:</p> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::math::geometry::+</b> <i class="arg">point1</i> <i class="arg">point2</i></a></dt> |
︙ | ︙ | |||
582 583 584 585 586 587 588 | <dd><p>Line to be checked</p></dd> <dt>list <i class="arg">circle</i></dt> <dd><p>Circle that may or may not be intersected</p></dd> </dl></dd> <dt><a name="47"><b class="cmd">::math::geometry::intersectionCircleWithCircle</b> <i class="arg">circle1</i> <i class="arg">circle2</i></a></dt> <dd><p>Determine the points at which the given two circles intersect. There can be zero, one or two points. (If the two circles touch the circle or are very close, | | | | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | <dd><p>Line to be checked</p></dd> <dt>list <i class="arg">circle</i></dt> <dd><p>Circle that may or may not be intersected</p></dd> </dl></dd> <dt><a name="47"><b class="cmd">::math::geometry::intersectionCircleWithCircle</b> <i class="arg">circle1</i> <i class="arg">circle2</i></a></dt> <dd><p>Determine the points at which the given two circles intersect. There can be zero, one or two points. (If the two circles touch the circle or are very close, then one point is returned. An arbitrary margin of 1.0e-10 times the mean of the radii of the two circles is used to determine this situation.)</p> <dl class="doctools_arguments"> <dt>list <i class="arg">circle1</i></dt> <dd><p>First circle</p></dd> <dt>list <i class="arg">circle2</i></dt> <dd><p>Second circle</p></dd> </dl></dd> <dt><a name="48"><b class="cmd">::math::geometry::tangentLinesToCircle</b> <i class="arg">point</i> <i class="arg">circle</i></a></dt> |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/math/numtheory.html.
1 2 3 4 5 6 7 | <div class='fossil-doc' data-title='math::numtheory - Tcl Math Library'> <style> HTML { background: #FFFFFF; color: black; } BODY { | > | 1 2 3 4 5 6 7 8 | <div class='fossil-doc' data-title='math::numtheory - Tcl Math Library'> <style> HTML { background: #FFFFFF; color: black; } BODY { |
︙ | ︙ | |||
94 95 96 97 98 99 100 | | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> | | | > > | | | | | | | | | | | | 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 | | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> <h1 class="doctools_title">math::numtheory(n) 1.1.1 tcllib "Tcl Math Library"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>math::numtheory - Number Theory</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl <span class="opt">?8.5?</span></b></li> <li>package require <b class="pkgname">math::numtheory <span class="opt">?1.1.1?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">math::numtheory::isprime</b> <i class="arg">N</i> <span class="opt">?<i class="arg">option</i> <i class="arg">value</i> ...?</span></a></li> <li><a href="#2"><b class="cmd">math::numtheory::firstNprimes</b> <i class="arg">N</i></a></li> <li><a href="#3"><b class="cmd">math::numtheory::primesLowerThan</b> <i class="arg">N</i></a></li> <li><a href="#4"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></li> <li><a href="#5"><b class="cmd">math::numtheory::primesLowerThan</b> <i class="arg">N</i></a></li> <li><a href="#6"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></li> <li><a href="#7"><b class="cmd">math::numtheory::uniquePrimeFactors</b> <i class="arg">N</i></a></li> <li><a href="#8"><b class="cmd">math::numtheory::factors</b> <i class="arg">N</i></a></li> <li><a href="#9"><b class="cmd">math::numtheory::totient</b> <i class="arg">N</i></a></li> <li><a href="#10"><b class="cmd">math::numtheory::moebius</b> <i class="arg">N</i></a></li> <li><a href="#11"><b class="cmd">math::numtheory::legendre</b> <i class="arg">a</i> <i class="arg">p</i></a></li> <li><a href="#12"><b class="cmd">math::numtheory::jacobi</b> <i class="arg">a</i> <i class="arg">b</i></a></li> <li><a href="#13"><b class="cmd">math::numtheory::gcd</b> <i class="arg">m</i> <i class="arg">n</i></a></li> <li><a href="#14"><b class="cmd">math::numtheory::lcm</b> <i class="arg">m</i> <i class="arg">n</i></a></li> <li><a href="#15"><b class="cmd">math::numtheory::numberPrimesGauss</b> <i class="arg">N</i></a></li> <li><a href="#16"><b class="cmd">math::numtheory::numberPrimesLegendre</b> <i class="arg">N</i></a></li> <li><a href="#17"><b class="cmd">math::numtheory::numberPrimesLegendreModified</b> <i class="arg">N</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This package is for collecting various number-theoretic operations, with a slight bias to prime numbers.</p> <dl class="doctools_definitions"> |
︙ | ︙ | |||
183 184 185 186 187 188 189 | </dl></dd> <dt><a name="4"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of the prime numbers in the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> | > > > > > > > > > > > > | | | | | | | | | | | | 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 | </dl></dd> <dt><a name="4"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of the prime numbers in the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> <dt><a name="5"><b class="cmd">math::numtheory::primesLowerThan</b> <i class="arg">N</i></a></dt> <dd><p>Return the prime numbers lower/equal to N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Maximum number to consider</p></dd> </dl></dd> <dt><a name="6"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of the prime numbers in the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> <dt><a name="7"><b class="cmd">math::numtheory::uniquePrimeFactors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of the <em>unique</em> prime numbers in the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> <dt><a name="8"><b class="cmd">math::numtheory::factors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of all <em>unique</em> factors in the number N, including 1 and N itself</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> <dt><a name="9"><b class="cmd">math::numtheory::totient</b> <i class="arg">N</i></a></dt> <dd><p>Evaluate the Euler totient function for the number N (number of numbers relatively prime to N)</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> <dt><a name="10"><b class="cmd">math::numtheory::moebius</b> <i class="arg">N</i></a></dt> <dd><p>Evaluate the Moebius function for the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> <dt><a name="11"><b class="cmd">math::numtheory::legendre</b> <i class="arg">a</i> <i class="arg">p</i></a></dt> <dd><p>Evaluate the Legendre symbol (a/p)</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">a</i> (in)</dt> <dd><p>Upper number in the symbol</p></dd> <dt>integer <i class="arg">p</i> (in)</dt> <dd><p>Lower number in the symbol (must be non-zero)</p></dd> </dl></dd> <dt><a name="12"><b class="cmd">math::numtheory::jacobi</b> <i class="arg">a</i> <i class="arg">b</i></a></dt> <dd><p>Evaluate the Jacobi symbol (a/b)</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">a</i> (in)</dt> <dd><p>Upper number in the symbol</p></dd> <dt>integer <i class="arg">b</i> (in)</dt> <dd><p>Lower number in the symbol (must be odd)</p></dd> </dl></dd> <dt><a name="13"><b class="cmd">math::numtheory::gcd</b> <i class="arg">m</i> <i class="arg">n</i></a></dt> <dd><p>Return the greatest common divisor of <i class="term">m</i> and <i class="term">n</i></p> <dl class="doctools_arguments"> <dt>integer <i class="arg">m</i> (in)</dt> <dd><p>First number</p></dd> <dt>integer <i class="arg">n</i> (in)</dt> <dd><p>Second number</p></dd> </dl></dd> <dt><a name="14"><b class="cmd">math::numtheory::lcm</b> <i class="arg">m</i> <i class="arg">n</i></a></dt> <dd><p>Return the lowest common multiple of <i class="term">m</i> and <i class="term">n</i></p> <dl class="doctools_arguments"> <dt>integer <i class="arg">m</i> (in)</dt> <dd><p>First number</p></dd> <dt>integer <i class="arg">n</i> (in)</dt> <dd><p>Second number</p></dd> </dl></dd> <dt><a name="15"><b class="cmd">math::numtheory::numberPrimesGauss</b> <i class="arg">N</i></a></dt> <dd><p>Estimate the number of primes according the formula by Gauss.</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> <dt><a name="16"><b class="cmd">math::numtheory::numberPrimesLegendre</b> <i class="arg">N</i></a></dt> <dd><p>Estimate the number of primes according the formula by Legendre.</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> <dt><a name="17"><b class="cmd">math::numtheory::numberPrimesLegendreModified</b> <i class="arg">N</i></a></dt> <dd><p>Estimate the number of primes according the modified formula by Legendre.</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> </dl> </div> |
︙ | ︙ |
Added embedded/www/tcllib/files/modules/math/trig.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | <div class='fossil-doc' data-title='math::trig - Tcl Math Library'> <style> HTML { background: #FFFFFF; color: black; } BODY { background: #FFFFFF; color: black; } DIV.doctools { margin-left: 10%; margin-right: 10%; } DIV.doctools H1,DIV.doctools H2 { margin-left: -5%; } H1, H2, H3, H4 { margin-top: 1em; font-family: sans-serif; font-size: large; color: #005A9C; background: transparent; text-align: left; } H1.doctools_title { text-align: center; } UL,OL { margin-right: 0em; margin-top: 3pt; margin-bottom: 3pt; } UL LI { list-style: disc; } OL LI { list-style: decimal; } DT { padding-top: 1ex; } UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL { font: normal 12pt/14pt sans-serif; list-style: none; } LI.doctools_section, LI.doctools_subsection { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } PRE { display: block; font-family: monospace; white-space: pre; margin: 0%; padding-top: 0.5ex; padding-bottom: 0.5ex; padding-left: 1ex; padding-right: 1ex; width: 100%; } PRE.doctools_example { color: black; background: #f5dcb3; border: 1px solid black; } UL.doctools_requirements LI, UL.doctools_syntax LI { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } DIV.doctools_synopsis { color: black; background: #80ffff; border: 1px solid black; font-family: serif; margin-top: 1em; margin-bottom: 1em; } UL.doctools_syntax { margin-top: 1em; border-top: 1px solid black; } UL.doctools_requirements { margin-bottom: 1em; border-bottom: 1px solid black; } </style> <hr> [ <a href="../../../../toc.html">Main Table Of Contents</a> | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> <h1 class="doctools_title">math::trig(n) 1.0.0 tcllib "Tcl Math Library"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>math::trig - Trigonometric anf hyperbolic functions</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">FUNCTIONS</a></li> <li class="doctools_section"><a href="#section3">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.5</b></li> <li>package require <b class="pkgname">math::trig 1.0.0</b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">::math::trig::radian_reduced</b> <i class="arg">angle</i></a></li> <li><a href="#2"><b class="cmd">::math::trig::degree_reduced</b> <i class="arg">angle</i></a></li> <li><a href="#3"><b class="cmd">::math::trig::cosec</b> <i class="arg">angle</i></a></li> <li><a href="#4"><b class="cmd">::math::trig::sec</b> <i class="arg">angle</i></a></li> <li><a href="#5"><b class="cmd">::math::trig::cotan</b> <i class="arg">angle</i></a></li> <li><a href="#6"><b class="cmd">::math::trig::acosec</b> <i class="arg">value</i></a></li> <li><a href="#7"><b class="cmd">::math::trig::asec</b> <i class="arg">value</i></a></li> <li><a href="#8"><b class="cmd">::math::trig::acotan</b> <i class="arg">value</i></a></li> <li><a href="#9"><b class="cmd">::math::trig::cosech</b> <i class="arg">value</i></a></li> <li><a href="#10"><b class="cmd">::math::trig::sech</b> <i class="arg">value</i></a></li> <li><a href="#11"><b class="cmd">::math::trig::cotanh</b> <i class="arg">value</i></a></li> <li><a href="#12"><b class="cmd">::math::trig::asinh</b> <i class="arg">value</i></a></li> <li><a href="#13"><b class="cmd">::math::trig::acosh</b> <i class="arg">value</i></a></li> <li><a href="#14"><b class="cmd">::math::trig::atanh</b> <i class="arg">value</i></a></li> <li><a href="#15"><b class="cmd">::math::trig::acosech</b> <i class="arg">value</i></a></li> <li><a href="#16"><b class="cmd">::math::trig::asech</b> <i class="arg">value</i></a></li> <li><a href="#17"><b class="cmd">::math::trig::acotanh</b> <i class="arg">value</i></a></li> <li><a href="#18"><b class="cmd">::math::trig::sind</b> <i class="arg">angle</i></a></li> <li><a href="#19"><b class="cmd">::math::trig::cosd</b> <i class="arg">angle</i></a></li> <li><a href="#20"><b class="cmd">::math::trig::tand</b> <i class="arg">angle</i></a></li> <li><a href="#21"><b class="cmd">::math::trig::cosecd</b> <i class="arg">angle</i></a></li> <li><a href="#22"><b class="cmd">::math::trig::secd</b> <i class="arg">angle</i></a></li> <li><a href="#23"><b class="cmd">::math::trig::cotand</b> <i class="arg">angle</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>The <i class="term">math::trig</i> package defines a set of trigonomic and hyperbolic functions and their inverses. In addition it defines versions of the trigonomic functions that take arguments in degrees instead of radians.</p> <p>For easy use these functions may be imported into the <i class="term">tcl::mathfunc</i> namespace, so that they can be used directly in the <i class="term">expr</i> command.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">FUNCTIONS</a></h2> <p>The functions <i class="term">radian_reduced</i> and <i class="term">degree_reduced</i> return a reduced angle, in respectively radians and degrees, in the intervals [0, 2pi) and [0, 360):</p> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::math::trig::radian_reduced</b> <i class="arg">angle</i></a></dt> <dd><p>Return the equivalent angle in the interval [0, 2pi).</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> <dt><a name="2"><b class="cmd">::math::trig::degree_reduced</b> <i class="arg">angle</i></a></dt> <dd><p>Return the equivalent angle in the interval [0, 360).</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> </dl> <p>The following trigonomic functions are defined in addition to the ones defined in the <i class="term">expr</i> command:</p> <dl class="doctools_definitions"> <dt><a name="3"><b class="cmd">::math::trig::cosec</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cosecant of the angle (1/cos(angle))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> <dt><a name="4"><b class="cmd">::math::trig::sec</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the secant of the angle (1/sin(angle))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> <dt><a name="5"><b class="cmd">::math::trig::cotan</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cotangent of the angle (1/tan(angle))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> </dl> <p>For these functions also the inverses are defined:</p> <dl class="doctools_definitions"> <dt><a name="6"><b class="cmd">::math::trig::acosec</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc cosecant of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="7"><b class="cmd">::math::trig::asec</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc secant of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="8"><b class="cmd">::math::trig::acotan</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc cotangent of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> </dl> <p>The following hyperbolic and inverse hyperbolic functions are defined:</p> <dl class="doctools_definitions"> <dt><a name="9"><b class="cmd">::math::trig::cosech</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the hyperbolic cosecant of the value (1/sinh(value))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="10"><b class="cmd">::math::trig::sech</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the hyperbolic secant of the value (1/cosh(value))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="11"><b class="cmd">::math::trig::cotanh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the hyperbolic cotangent of the value (1/tanh(value))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="12"><b class="cmd">::math::trig::asinh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic sine of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="13"><b class="cmd">::math::trig::acosh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic cosine of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="14"><b class="cmd">::math::trig::atanh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic tangent of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="15"><b class="cmd">::math::trig::acosech</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic cosecant of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="16"><b class="cmd">::math::trig::asech</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic secant of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="17"><b class="cmd">::math::trig::acotanh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic cotangent of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> </dl> <p>The following versions of the common trigonometric functions and their inverses are defined:</p> <dl class="doctools_definitions"> <dt><a name="18"><b class="cmd">::math::trig::sind</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the sine of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> <dt><a name="19"><b class="cmd">::math::trig::cosd</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cosine of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> <dt><a name="20"><b class="cmd">::math::trig::tand</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cotangent of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> <dt><a name="21"><b class="cmd">::math::trig::cosecd</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cosecant of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> <dt><a name="22"><b class="cmd">::math::trig::secd</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the secant of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> <dt><a name="23"><b class="cmd">::math::trig::cotand</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cotangent of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>math :: trig</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. Please also report any ideas for enhancements you may have for either package and/or documentation.</p> <p>When proposing code changes, please provide <em>unified diffs</em>, i.e the output of <b class="const">diff -u</b>.</p> <p>Note further that <em>attachments</em> are strongly preferred over inlined patches. Attachments can be made by going to the <b class="const">Edit</b> form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p><a href="../../../../index.html#math">math</a>, <a href="../../../../index.html#trigonometry">trigonometry</a></p> </div> <div id="category" class="doctools_section"><h2><a name="category">Category</a></h2> <p>Mathematics</p> </div> <div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> <p>Copyright © 2018 Arjen Markus</p> </div> </div> |
Changes to embedded/www/tcllib/files/modules/nns/nns_client.html.
︙ | ︙ | |||
219 220 221 222 223 224 225 | be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="8"><b class="cmd">::nameserv::configure</b></a></dt> <dd><p>In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="9"><b class="cmd">::nameserv::configure</b> <b class="option">-option</b></a></dt> <dd><p>In this form the command is an alias for | | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="8"><b class="cmd">::nameserv::configure</b></a></dt> <dd><p>In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="9"><b class="cmd">::nameserv::configure</b> <b class="option">-option</b></a></dt> <dd><p>In this form the command is an alias for "<b class="cmd">::nameserv::cget</b> <b class="option">-option</b>". The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="10"><b class="cmd">::nameserv::configure</b> <b class="option">-option</b> <i class="arg">value</i>...</a></dt> <dd><p>In this form the command is used to configure one or more of the supported options. At least one option has to be specified, and each option is followed by its new value. The list of supported options and their meaning can be found in |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/nns/nns_server.html.
︙ | ︙ | |||
174 175 176 177 178 179 180 | be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="5"><b class="cmd">::nameserv::server::configure</b></a></dt> <dd><p>In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="6"><b class="cmd">::nameserv::server::configure</b> <b class="option">-option</b></a></dt> <dd><p>In this form the command is an alias for | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="5"><b class="cmd">::nameserv::server::configure</b></a></dt> <dd><p>In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="6"><b class="cmd">::nameserv::server::configure</b> <b class="option">-option</b></a></dt> <dd><p>In this form the command is an alias for "<b class="cmd">::nameserv::server::cget</b> <b class="option">-option</b>". The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="7"><b class="cmd">::nameserv::server::configure</b> <b class="option">-option</b> <i class="arg">value</i>...</a></dt> <dd><p>In this form the command is used to configure one or more of the supported options. At least one option has to be specified, and each option is followed by its new value. The list of supported options and their meaning can be found in |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/oometa/oometa.html.
︙ | ︙ | |||
233 234 235 236 237 238 239 | <dt><a name="11"><b class="cmd">oo::object method meta</b></a></dt> <dd><p>The package injects a new method <b class="cmd">meta</b> into <b class="cmd">oo::object</b>. <b class="cmd">oo::object</b> combines the data for its class (as provided by <b class="cmd">oo::meta::metadata</b>), with a local variable <em>meta</em> to produce a local picture of metadata. This method provides the following additional commands:</p></dd> <dt><a name="12"><b class="cmd">oo::object method meta cget</b> <span class="opt">?<i class="arg">field</i>?</span> <span class="opt">?<i class="arg">...</i>?</span> <i class="arg">field</i></a></dt> <dd><p>Attempts to locate a singlar leaf, and return its value. For single option lookups, this | | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | <dt><a name="11"><b class="cmd">oo::object method meta</b></a></dt> <dd><p>The package injects a new method <b class="cmd">meta</b> into <b class="cmd">oo::object</b>. <b class="cmd">oo::object</b> combines the data for its class (as provided by <b class="cmd">oo::meta::metadata</b>), with a local variable <em>meta</em> to produce a local picture of metadata. This method provides the following additional commands:</p></dd> <dt><a name="12"><b class="cmd">oo::object method meta cget</b> <span class="opt">?<i class="arg">field</i>?</span> <span class="opt">?<i class="arg">...</i>?</span> <i class="arg">field</i></a></dt> <dd><p>Attempts to locate a singlar leaf, and return its value. For single option lookups, this is faster than <b class="cmd">my meta getnull</b> <span class="opt">?<i class="arg">field</i>?</span> <span class="opt">?<i class="arg">...</i>?</span> <i class="arg">field</i>, because it performs a search instead directly instead of producing the recursive merge product between the class metadata, the local <em>meta</em> variable, and THEN performing the search.</p></dd> </dl> </div> <div id="section5" class="doctools_section"><h2><a name="section5">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/pop3d/pop3d.html.
︙ | ︙ | |||
264 265 266 267 268 269 270 | <p>Here we describe the interface which has to be provided by the storage callback so that pop3 servers following the interface of this module are able to use it. The <i class="arg">mbox</i> argument is the storage reference as returned by the <b class="method">lookup</b> method of the authentication command, see section <span class="sectref"><a href="#section3">Authentication</a></span>.</p> <dl class="doctools_definitions"> <dt><a name="14"><i class="arg">storageCmd</i> <b class="method">dele</b> <i class="arg">mbox</i> <i class="arg">msgList</i></a></dt> | < | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | <p>Here we describe the interface which has to be provided by the storage callback so that pop3 servers following the interface of this module are able to use it. The <i class="arg">mbox</i> argument is the storage reference as returned by the <b class="method">lookup</b> method of the authentication command, see section <span class="sectref"><a href="#section3">Authentication</a></span>.</p> <dl class="doctools_definitions"> <dt><a name="14"><i class="arg">storageCmd</i> <b class="method">dele</b> <i class="arg">mbox</i> <i class="arg">msgList</i></a></dt> <dd><p>Deletes the messages whose numeric ids are contained in the <i class="arg">msgList</i> from the mailbox specified via <i class="arg">mbox</i>.</p></dd> <dt><a name="15"><i class="arg">storageCmd</i> <b class="method">lock</b> <i class="arg">mbox</i></a></dt> <dd><p>This method locks the specified mailbox for use by a single connection to the server. This is necessary to prevent havoc if several connections to the same mailbox are open. The complementary method is <b class="method">unlock</b>. The command will return true if the lock could be set successfully or false if not.</p></dd> |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/practcl/practcl.html.
1 |
| > | | | 1 2 3 4 5 6 7 8 9 10 11 | <!DOCTYPE html><html><head> <title>practcl - The The Proper Rational API for C to Tool Command Language Module</title> <style type="text/css"><!-- HTML { background: #FFFFFF; color: black; } BODY { background: #FFFFFF; color: black; |
︙ | ︙ | |||
85 86 87 88 89 90 91 | margin-top: 1em; border-top: 1px solid black; } UL.doctools_requirements { margin-bottom: 1em; border-bottom: 1px solid black; } | | | | < > | < < < > | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < < > > > > | | | | | | | | | | < < < < < < > | | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 | margin-top: 1em; border-top: 1px solid black; } UL.doctools_requirements { margin-bottom: 1em; border-bottom: 1px solid black; } --></style> </head> <!-- Generated from file 'practcl.man' by tcllib/doctools with format 'html' --> <!-- Copyright &copy; 2016-2018 Sean Woods &lt;yoda@etoyoc.com&gt; --> <!-- practcl.n --> <body><div class="doctools"> <h1 class="doctools_title">practcl(n) 0.12 practcl "The The Proper Rational API for C to Tool Command Language Module"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>practcl - The Practcl Module</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">Commands</a></li> <li class="doctools_section"><a href="#section3">Classes</a> <ul> <li class="doctools_subsection"><a href="#subsection1">Class practcl::metaclass</a></li> <li class="doctools_subsection"><a href="#subsection2">Class practcl::toolset</a></li> <li class="doctools_subsection"><a href="#subsection3">Class practcl::toolset.gcc</a></li> <li class="doctools_subsection"><a href="#subsection4">Class practcl::toolset.msvc</a></li> <li class="doctools_subsection"><a href="#subsection5">Class practcl::make_obj</a></li> <li class="doctools_subsection"><a href="#subsection6">Class practcl::object</a></li> <li class="doctools_subsection"><a href="#subsection7">Class practcl::dynamic</a></li> <li class="doctools_subsection"><a href="#subsection8">Class practcl::product</a></li> <li class="doctools_subsection"><a href="#subsection9">Class practcl::product.cheader</a></li> <li class="doctools_subsection"><a href="#subsection10">Class practcl::product.csource</a></li> <li class="doctools_subsection"><a href="#subsection11">Class practcl::product.clibrary</a></li> <li class="doctools_subsection"><a href="#subsection12">Class practcl::product.dynamic</a></li> <li class="doctools_subsection"><a href="#subsection13">Class practcl::product.critcl</a></li> <li class="doctools_subsection"><a href="#subsection14">Class practcl::module</a></li> <li class="doctools_subsection"><a href="#subsection15">Class practcl::project</a></li> <li class="doctools_subsection"><a href="#subsection16">Class practcl::library</a></li> <li class="doctools_subsection"><a href="#subsection17">Class practcl::tclkit</a></li> <li class="doctools_subsection"><a href="#subsection18">Class practcl::distribution</a></li> <li class="doctools_subsection"><a href="#subsection19">Class practcl::distribution.snapshot</a></li> <li class="doctools_subsection"><a href="#subsection20">Class practcl::distribution.fossil</a></li> <li class="doctools_subsection"><a href="#subsection21">Class practcl::distribution.git</a></li> <li class="doctools_subsection"><a href="#subsection22">Class practcl::subproject</a></li> <li class="doctools_subsection"><a href="#subsection23">Class practcl::subproject.source</a></li> <li class="doctools_subsection"><a href="#subsection24">Class practcl::subproject.teapot</a></li> <li class="doctools_subsection"><a href="#subsection25">Class practcl::subproject.kettle</a></li> <li class="doctools_subsection"><a href="#subsection26">Class practcl::subproject.critcl</a></li> <li class="doctools_subsection"><a href="#subsection27">Class practcl::subproject.sak</a></li> <li class="doctools_subsection"><a href="#subsection28">Class practcl::subproject.binary</a></li> <li class="doctools_subsection"><a href="#subsection29">Class practcl::subproject.tea</a></li> <li class="doctools_subsection"><a href="#subsection30">Class practcl::subproject.library</a></li> <li class="doctools_subsection"><a href="#subsection31">Class practcl::subproject.external</a></li> <li class="doctools_subsection"><a href="#subsection32">Class practcl::subproject.core</a></li> </ul> </li> <li class="doctools_section"><a href="#section4">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">TclOO 1.0</b></li> <li>package require <b class="pkgname">practcl 0.12</b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1">proc <b class="cmd">Proc</b> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></li> <li><a href="#2">proc <b class="cmd">noop</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#3">proc <b class="cmd">practcl::debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#4">proc <b class="cmd">practcl::doexec</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#5">proc <b class="cmd">practcl::doexec_in</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#6">proc <b class="cmd">practcl::dotclexec</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#7">proc <b class="cmd">practcl::domake</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#8">proc <b class="cmd">practcl::domake.tcl</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#9">proc <b class="cmd">practcl::fossil</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#10">proc <b class="cmd">practcl::fossil_status</b> <i class="arg">dir</i></a></li> <li><a href="#11">proc <b class="cmd">practcl::os</b></a></li> <li><a href="#12">proc <b class="cmd">practcl::mkzip</b> <i class="arg">exename</i> <i class="arg">barekit</i> <i class="arg">vfspath</i></a></li> <li><a href="#13">proc <b class="cmd">practcl::sort_dict</b> <i class="arg">list</i></a></li> <li><a href="#14">proc <b class="cmd">practcl::local_os</b></a></li> <li><a href="#15">proc <b class="cmd">practcl::config.tcl</b> <i class="arg">path</i></a></li> <li><a href="#16">proc <b class="cmd">practcl::read_configuration</b> <i class="arg">path</i></a></li> <li><a href="#17">proc <b class="cmd">practcl::tcllib_require</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#18">proc <b class="cmd">practcl::platform::tcl_core_options</b> <i class="arg">os</i></a></li> <li><a href="#19">proc <b class="cmd">practcl::platform::tk_core_options</b> <i class="arg">os</i></a></li> <li><a href="#20">proc <b class="cmd">practcl::read_rc_file</b> <i class="arg">filename</i> <span class="opt">?<i class="arg">localdat</i> <b class="const"></b>?</span></a></li> <li><a href="#21">proc <b class="cmd">practcl::read_sh_subst</b> <i class="arg">line</i> <i class="arg">info</i></a></li> <li><a href="#22">proc <b class="cmd">practcl::read_sh_file</b> <i class="arg">filename</i> <span class="opt">?<i class="arg">localdat</i> <b class="const"></b>?</span></a></li> <li><a href="#23">proc <b class="cmd">practcl::read_Config.sh</b> <i class="arg">filename</i></a></li> <li><a href="#24">proc <b class="cmd">practcl::read_Makefile</b> <i class="arg">filename</i></a></li> <li><a href="#25">proc <b class="cmd">practcl::cputs</b> <i class="arg">varname</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#26">proc <b class="cmd">practcl::tcl_to_c</b> <i class="arg">body</i></a></li> <li><a href="#27">proc <b class="cmd">practcl::_tagblock</b> <i class="arg">text</i> <span class="opt">?<i class="arg">style</i> <b class="const">tcl</b>?</span> <span class="opt">?<i class="arg">note</i> <b class="const"></b>?</span></a></li> <li><a href="#28">proc <b class="cmd">practcl::de_shell</b> <i class="arg">data</i></a></li> <li><a href="#29">proc <b class="cmd">practcl::cat</b> <i class="arg">fname</i></a></li> <li><a href="#30">proc <b class="cmd">practcl::grep</b> <i class="arg">pattern</i> <span class="opt">?<i class="arg">files</i> <b class="const"></b>?</span></a></li> <li><a href="#31">proc <b class="cmd">practcl::file_lexnormalize</b> <i class="arg">sp</i></a></li> <li><a href="#32">proc <b class="cmd">practcl::file_relative</b> <i class="arg">base</i> <i class="arg">dst</i></a></li> <li><a href="#33">proc <b class="cmd">practcl::log</b> <i class="arg">fname</i> <i class="arg">comment</i></a></li> <li><a href="#34">proc <b class="cmd">practcl::_isdirectory</b> <i class="arg">name</i></a></li> <li><a href="#35">proc <b class="cmd">practcl::_pkgindex_directory</b> <i class="arg">path</i></a></li> <li><a href="#36">proc <b class="cmd">practcl::_pkgindex_path_subdir</b> <i class="arg">path</i></a></li> <li><a href="#37">proc <b class="cmd">practcl::pkgindex_path</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#38">proc <b class="cmd">practcl::installDir</b> <i class="arg">d1</i> <i class="arg">d2</i></a></li> <li><a href="#39">proc <b class="cmd">practcl::copyDir</b> <i class="arg">d1</i> <i class="arg">d2</i> <span class="opt">?<i class="arg">toplevel</i> <b class="const">1</b>?</span></a></li> <li><a href="#40">proc <b class="cmd">practcl::trigger</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#41">proc <b class="cmd">practcl::depends</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#42">proc <b class="cmd">practcl::target</b> <i class="arg">name</i> <i class="arg">info</i> <span class="opt">?<i class="arg">action</i> <b class="const"></b>?</span></a></li> <li><a href="#43">method <b class="cmd">_MorphPatterns</b></a></li> <li><a href="#44">method <b class="cmd">define</b> <i class="arg">submethod</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#45">method <b class="cmd">graft</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#46">method <b class="cmd">initialize</b></a></li> <li><a href="#47">method <b class="cmd">link</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#48">method <b class="cmd">morph</b> <i class="arg">classname</i></a></li> <li><a href="#49">method <b class="cmd">mixin</b> <i class="arg">slot</i> <i class="arg">classname</i></a></li> <li><a href="#50">method <b class="cmd">organ</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#51">method <b class="cmd">script</b> <i class="arg">script</i></a></li> <li><a href="#52">method <b class="cmd">select</b></a></li> <li><a href="#53">method <b class="cmd">source</b> <i class="arg">filename</i></a></li> <li><a href="#54">method <b class="cmd">select</b> <i class="arg">object</i></a></li> <li><a href="#55">method <b class="cmd">config.sh</b></a></li> <li><a href="#56">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#57">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></li> <li><a href="#58">method <b class="cmd">read_configuration</b></a></li> <li><a href="#59">method <b class="cmd">build-cflags</b> <i class="arg">PROJECT</i> <i class="arg">DEFS</i> <i class="arg">namevar</i> <i class="arg">versionvar</i> <i class="arg">defsvar</i></a></li> <li><a href="#60">method <b class="cmd">critcl</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#61">method <b class="cmd">make-autodetect</b></a></li> <li><a href="#62">method <b class="cmd">Autoconf</b></a></li> <li><a href="#63">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#64">method <b class="cmd">ConfigureOpts</b></a></li> <li><a href="#65">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></li> <li><a href="#66">method <b class="cmd">make-autodetect</b></a></li> <li><a href="#67">method <b class="cmd">make-clean</b></a></li> <li><a href="#68">method <b class="cmd">make-compile</b></a></li> <li><a href="#69">method <b class="cmd">make-install</b> <i class="arg">DEST</i></a></li> <li><a href="#70">method <b class="cmd">build-compile-sources</b> <i class="arg">PROJECT</i> <i class="arg">COMPILE</i> <i class="arg">CPPCOMPILE</i> <i class="arg">INCLUDES</i></a></li> <li><a href="#71">method <b class="cmd">build-Makefile</b> <i class="arg">path</i> <i class="arg">PROJECT</i></a></li> <li><a href="#72">method <b class="cmd">build-library</b> <i class="arg">outfile</i> <i class="arg">PROJECT</i></a></li> <li><a href="#73">method <b class="cmd">build-tclsh</b> <i class="arg">outfile</i> <i class="arg">PROJECT</i></a></li> <li><a href="#74">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#75">method <b class="cmd">make-autodetect</b></a></li> <li><a href="#76">method <b class="cmd">make-clean</b></a></li> <li><a href="#77">method <b class="cmd">make-compile</b></a></li> <li><a href="#78">method <b class="cmd">make-install</b> <i class="arg">DEST</i></a></li> <li><a href="#79">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></li> <li><a href="#80">method <b class="cmd">NmakeOpts</b></a></li> <li><a href="#81">method <b class="cmd">constructor</b> <i class="arg">module_object</i> <i class="arg">name</i> <i class="arg">info</i> <span class="opt">?<i class="arg">action_body</i> <b class="const"></b>?</span></a></li> <li><a href="#82">method <b class="cmd">do</b></a></li> <li><a href="#83">method <b class="cmd">check</b></a></li> <li><a href="#84">method <b class="cmd">output</b></a></li> <li><a href="#85">method <b class="cmd">reset</b></a></li> <li><a href="#86">method <b class="cmd">triggers</b></a></li> <li><a href="#87">method <b class="cmd">constructor</b> <i class="arg">parent</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#88">method <b class="cmd">child</b> <i class="arg">method</i></a></li> <li><a href="#89">method <b class="cmd">go</b></a></li> <li><a href="#90">method <b class="cmd">cstructure</b> <i class="arg">name</i> <i class="arg">definition</i> <span class="opt">?<i class="arg">argdat</i> <b class="const"></b>?</span></a></li> <li><a href="#91">method <b class="cmd">include</b> <i class="arg">header</i></a></li> <li><a href="#92">method <b class="cmd">include_dir</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#93">method <b class="cmd">include_directory</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#94">method <b class="cmd">c_header</b> <i class="arg">body</i></a></li> <li><a href="#95">method <b class="cmd">c_code</b> <i class="arg">body</i></a></li> <li><a href="#96">method <b class="cmd">c_function</b> <i class="arg">header</i> <i class="arg">body</i> <span class="opt">?<i class="arg">info</i> <b class="const"></b>?</span></a></li> <li><a href="#97">method <b class="cmd">c_tcloomethod</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></li> <li><a href="#98">method <b class="cmd">cmethod</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></li> <li><a href="#99">method <b class="cmd">c_tclproc_nspace</b> <i class="arg">nspace</i></a></li> <li><a href="#100">method <b class="cmd">c_tclcmd</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></li> <li><a href="#101">method <b class="cmd">c_tclproc_raw</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></li> <li><a href="#102">method <b class="cmd">tcltype</b> <i class="arg">name</i> <i class="arg">argdat</i></a></li> <li><a href="#103">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#104">method <b class="cmd">implement</b> <i class="arg">path</i></a></li> <li><a href="#105">method <b class="cmd">initialize</b></a></li> <li><a href="#106">method <b class="cmd">linktype</b></a></li> <li><a href="#107">method <b class="cmd">generate-cfile-constant</b></a></li> <li><a href="#108">method <b class="cmd">generate-cfile-header</b></a></li> <li><a href="#109">method <b class="cmd">generate-cfile-tclapi</b></a></li> <li><a href="#110">method <b class="cmd">generate-loader-module</b></a></li> <li><a href="#111">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></li> <li><a href="#112">method <b class="cmd">select</b></a></li> <li><a href="#113">method <b class="cmd">select</b> <i class="arg">object</i></a></li> <li><a href="#114">method <b class="cmd">code</b> <i class="arg">section</i> <i class="arg">body</i></a></li> <li><a href="#115">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></li> <li><a href="#116">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#117">method <b class="cmd">generate-debug</b> <span class="opt">?<i class="arg">spaces</i> <b class="const"></b>?</span></a></li> <li><a href="#118">method <b class="cmd">generate-cfile-constant</b></a></li> <li><a href="#119">method <b class="cmd">generate-cfile-public-structure</b></a></li> <li><a href="#120">method <b class="cmd">generate-cfile-header</b></a></li> <li><a href="#121">method <b class="cmd">generate-cfile-global</b></a></li> <li><a href="#122">method <b class="cmd">generate-cfile-private-typedef</b></a></li> <li><a href="#123">method <b class="cmd">generate-cfile-private-structure</b></a></li> <li><a href="#124">method <b class="cmd">generate-cfile-functions</b></a></li> <li><a href="#125">method <b class="cmd">generate-cfile-tclapi</b></a></li> <li><a href="#126">method <b class="cmd">generate-hfile-public-define</b></a></li> <li><a href="#127">method <b class="cmd">generate-hfile-public-macro</b></a></li> <li><a href="#128">method <b class="cmd">generate-hfile-public-typedef</b></a></li> <li><a href="#129">method <b class="cmd">generate-hfile-public-structure</b></a></li> <li><a href="#130">method <b class="cmd">generate-hfile-public-headers</b></a></li> <li><a href="#131">method <b class="cmd">generate-hfile-public-function</b></a></li> <li><a href="#132">method <b class="cmd">generate-hfile-public-includes</b></a></li> <li><a href="#133">method <b class="cmd">generate-hfile-public-verbatim</b></a></li> <li><a href="#134">method <b class="cmd">generate-loader-external</b></a></li> <li><a href="#135">method <b class="cmd">generate-loader-module</b></a></li> <li><a href="#136">method <b class="cmd">generate-stub-function</b></a></li> <li><a href="#137">method <b class="cmd">IncludeAdd</b> <i class="arg">headervar</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#138">method <b class="cmd">generate-tcl-loader</b></a></li> <li><a href="#139">method <b class="cmd">generate-tcl-pre</b></a></li> <li><a href="#140">method <b class="cmd">generate-tcl-post</b></a></li> <li><a href="#141">method <b class="cmd">linktype</b></a></li> <li><a href="#142">method <b class="cmd">Ofile</b> <i class="arg">filename</i></a></li> <li><a href="#143">method <b class="cmd">project-static-packages</b></a></li> <li><a href="#144">method <b class="cmd">toolset-include-directory</b></a></li> <li><a href="#145">method <b class="cmd">target</b> <i class="arg">method</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#146">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#147">method <b class="cmd">generate-loader-module</b></a></li> <li><a href="#148">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#149">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></li> <li><a href="#150">method <b class="cmd">initialize</b></a></li> <li><a href="#151">method <b class="cmd">_MorphPatterns</b></a></li> <li><a href="#152">method <b class="cmd">add</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#153">method <b class="cmd">install-headers</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#154">method <b class="cmd">make</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#155">method <b class="cmd">child</b> <i class="arg">which</i></a></li> <li><a href="#156">method <b class="cmd">generate-c</b></a></li> <li><a href="#157">method <b class="cmd">generate-h</b></a></li> <li><a href="#158">method <b class="cmd">generate-loader</b></a></li> <li><a href="#159">method <b class="cmd">initialize</b></a></li> <li><a href="#160">method <b class="cmd">implement</b> <i class="arg">path</i></a></li> <li><a href="#161">method <b class="cmd">linktype</b></a></li> <li><a href="#162">method <b class="cmd">_MorphPatterns</b></a></li> <li><a href="#163">method <b class="cmd">constructor</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#164">method <b class="cmd">add_object</b> <i class="arg">object</i></a></li> <li><a href="#165">method <b class="cmd">add_project</b> <i class="arg">pkg</i> <i class="arg">info</i> <span class="opt">?<i class="arg">oodefine</i> <b class="const"></b>?</span></a></li> <li><a href="#166">method <b class="cmd">add_tool</b> <i class="arg">pkg</i> <i class="arg">info</i> <span class="opt">?<i class="arg">oodefine</i> <b class="const"></b>?</span></a></li> <li><a href="#167">method <b class="cmd">build-tclcore</b></a></li> <li><a href="#168">method <b class="cmd">child</b> <i class="arg">which</i></a></li> <li><a href="#169">method <b class="cmd">linktype</b></a></li> <li><a href="#170">method <b class="cmd">project</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#171">method <b class="cmd">tclcore</b></a></li> <li><a href="#172">method <b class="cmd">tkcore</b></a></li> <li><a href="#173">method <b class="cmd">tool</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#174">method <b class="cmd">clean</b> <i class="arg">PATH</i></a></li> <li><a href="#175">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#176">method <b class="cmd">go</b></a></li> <li><a href="#177">method <b class="cmd">generate-decls</b> <i class="arg">pkgname</i> <i class="arg">path</i></a></li> <li><a href="#178">method <b class="cmd">implement</b> <i class="arg">path</i></a></li> <li><a href="#179">method <b class="cmd">generate-make</b> <i class="arg">path</i></a></li> <li><a href="#180">method <b class="cmd">linktype</b></a></li> <li><a href="#181">method <b class="cmd">package-ifneeded</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#182">method <b class="cmd">shared_library</b> <span class="opt">?<i class="arg">filename</i> <b class="const"></b>?</span></a></li> <li><a href="#183">method <b class="cmd">static_library</b> <span class="opt">?<i class="arg">filename</i> <b class="const"></b>?</span></a></li> <li><a href="#184">method <b class="cmd">build-tclkit_main</b> <i class="arg">PROJECT</i> <i class="arg">PKG_OBJS</i></a></li> <li><a href="#185">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></li> <li><a href="#186">method <b class="cmd">wrap</b> <i class="arg">PWD</i> <i class="arg">exename</i> <i class="arg">vfspath</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#187">method <b class="cmd">Sandbox</b> <i class="arg">object</i></a></li> <li><a href="#188">method <b class="cmd">select</b> <i class="arg">object</i></a></li> <li><a href="#189">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></li> <li><a href="#190">method <b class="cmd">claim_object</b> <i class="arg">object</i></a></li> <li><a href="#191">method <b class="cmd">scm_info</b></a></li> <li><a href="#192">method <b class="cmd">DistroMixIn</b></a></li> <li><a href="#193">method <b class="cmd">Sandbox</b></a></li> <li><a href="#194">method <b class="cmd">SrcDir</b></a></li> <li><a href="#195">method <b class="cmd">ScmTag</b></a></li> <li><a href="#196">method <b class="cmd">ScmClone</b></a></li> <li><a href="#197">method <b class="cmd">ScmUnpack</b></a></li> <li><a href="#198">method <b class="cmd">ScmUpdate</b></a></li> <li><a href="#199">method <b class="cmd">Unpack</b></a></li> <li><a href="#200">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></li> <li><a href="#201">method <b class="cmd">claim_object</b> <i class="arg">object</i></a></li> <li><a href="#202">method <b class="cmd">ScmUnpack</b></a></li> <li><a href="#203">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></li> <li><a href="#204">method <b class="cmd">claim_object</b> <i class="arg">obj</i></a></li> <li><a href="#205">method <b class="cmd">scm_info</b></a></li> <li><a href="#206">method <b class="cmd">ScmClone</b></a></li> <li><a href="#207">method <b class="cmd">ScmTag</b></a></li> <li><a href="#208">method <b class="cmd">ScmUnpack</b></a></li> <li><a href="#209">method <b class="cmd">ScmUpdate</b></a></li> <li><a href="#210">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></li> <li><a href="#211">method <b class="cmd">claim_object</b> <i class="arg">obj</i></a></li> <li><a href="#212">method <b class="cmd">ScmTag</b></a></li> <li><a href="#213">method <b class="cmd">ScmUnpack</b></a></li> <li><a href="#214">method <b class="cmd">ScmUpdate</b></a></li> <li><a href="#215">method <b class="cmd">_MorphPatterns</b></a></li> <li><a href="#216">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#217">method <b class="cmd">child</b> <i class="arg">which</i></a></li> <li><a href="#218">method <b class="cmd">compile</b></a></li> <li><a href="#219">method <b class="cmd">go</b></a></li> <li><a href="#220">method <b class="cmd">install</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#221">method <b class="cmd">linktype</b></a></li> <li><a href="#222">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></li> <li><a href="#223">method <b class="cmd">linker-external</b> <i class="arg">configdict</i></a></li> <li><a href="#224">method <b class="cmd">linker-extra</b> <i class="arg">configdict</i></a></li> <li><a href="#225">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#226">method <b class="cmd">env-exec</b></a></li> <li><a href="#227">method <b class="cmd">env-install</b></a></li> <li><a href="#228">method <b class="cmd">env-load</b></a></li> <li><a href="#229">method <b class="cmd">env-present</b></a></li> <li><a href="#230">method <b class="cmd">sources</b></a></li> <li><a href="#231">method <b class="cmd">update</b></a></li> <li><a href="#232">method <b class="cmd">unpack</b></a></li> <li><a href="#233">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#234">method <b class="cmd">env-present</b></a></li> <li><a href="#235">method <b class="cmd">linktype</b></a></li> <li><a href="#236">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#237">method <b class="cmd">env-install</b></a></li> <li><a href="#238">method <b class="cmd">env-present</b></a></li> <li><a href="#239">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#240">method <b class="cmd">kettle</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#241">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#242">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#243">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#244">method <b class="cmd">env-install</b></a></li> <li><a href="#245">method <b class="cmd">env-present</b></a></li> <li><a href="#246">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#247">method <b class="cmd">install-module</b> <i class="arg">DEST</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#248">method <b class="cmd">clean</b></a></li> <li><a href="#249">method <b class="cmd">env-install</b></a></li> <li><a href="#250">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#251">method <b class="cmd">ComputeInstall</b></a></li> <li><a href="#252">method <b class="cmd">go</b></a></li> <li><a href="#253">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></li> <li><a href="#254">method <b class="cmd">project-static-packages</b></a></li> <li><a href="#255">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#256">method <b class="cmd">compile</b></a></li> <li><a href="#257">method <b class="cmd">Configure</b></a></li> <li><a href="#258">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#259">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#260">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#261">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#262">method <b class="cmd">env-present</b></a></li> <li><a href="#263">method <b class="cmd">env-install</b></a></li> <li><a href="#264">method <b class="cmd">go</b></a></li> <li><a href="#265">method <b class="cmd">linktype</b></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>The Practcl module is a tool for integrating large modules for C API Tcl code that requires custom Tcl types and TclOO objects.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">Commands</a></h2> <dl class="doctools_definitions"> <dt><a name="1">proc <b class="cmd">Proc</b> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd><p>Generate a proc if no command already exists by that name</p></dd> <dt><a name="2">proc <b class="cmd">noop</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>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</p></dd> <dt><a name="3">proc <b class="cmd">practcl::debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="4">proc <b class="cmd">practcl::doexec</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Drop in a static copy of Tcl</p></dd> <dt><a name="5">proc <b class="cmd">practcl::doexec_in</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="6">proc <b class="cmd">practcl::dotclexec</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="7">proc <b class="cmd">practcl::domake</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="8">proc <b class="cmd">practcl::domake.tcl</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="9">proc <b class="cmd">practcl::fossil</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="10">proc <b class="cmd">practcl::fossil_status</b> <i class="arg">dir</i></a></dt> <dd></dd> <dt><a name="11">proc <b class="cmd">practcl::os</b></a></dt> <dd></dd> <dt><a name="12">proc <b class="cmd">practcl::mkzip</b> <i class="arg">exename</i> <i class="arg">barekit</i> <i class="arg">vfspath</i></a></dt> <dd><p>Build a zipfile. On tcl8.6 this invokes the native Zip implementation on older interpreters this invokes zip via exec</p></dd> <dt><a name="13">proc <b class="cmd">practcl::sort_dict</b> <i class="arg">list</i></a></dt> <dd><p>Dictionary sort a key/value list. Needed because pre tcl8.6 does not have <em>lsort -stride 2</em></p></dd> <dt><a name="14">proc <b class="cmd">practcl::local_os</b></a></dt> <dd></dd> <dt><a name="15">proc <b class="cmd">practcl::config.tcl</b> <i class="arg">path</i></a></dt> <dd><p>Detect local platform</p></dd> <dt><a name="16">proc <b class="cmd">practcl::read_configuration</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="17">proc <b class="cmd">practcl::tcllib_require</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Try to load a package, and failing that retrieve tcllib</p></dd> <dt><a name="18">proc <b class="cmd">practcl::platform::tcl_core_options</b> <i class="arg">os</i></a></dt> <dd></dd> <dt><a name="19">proc <b class="cmd">practcl::platform::tk_core_options</b> <i class="arg">os</i></a></dt> <dd></dd> <dt><a name="20">proc <b class="cmd">practcl::read_rc_file</b> <i class="arg">filename</i> <span class="opt">?<i class="arg">localdat</i> <b class="const"></b>?</span></a></dt> <dd><p>Read a stylized key/value list stored in a file</p></dd> <dt><a name="21">proc <b class="cmd">practcl::read_sh_subst</b> <i class="arg">line</i> <i class="arg">info</i></a></dt> <dd></dd> <dt><a name="22">proc <b class="cmd">practcl::read_sh_file</b> <i class="arg">filename</i> <span class="opt">?<i class="arg">localdat</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="23">proc <b class="cmd">practcl::read_Config.sh</b> <i class="arg">filename</i></a></dt> <dd><p>A simpler form of read_sh_file tailored to pulling data from (tcl|tk)Config.sh</p></dd> <dt><a name="24">proc <b class="cmd">practcl::read_Makefile</b> <i class="arg">filename</i></a></dt> <dd><p>A simpler form of read_sh_file tailored to pulling data from a Makefile</p></dd> <dt><a name="25">proc <b class="cmd">practcl::cputs</b> <i class="arg">varname</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>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</p></dd> <dt><a name="26">proc <b class="cmd">practcl::tcl_to_c</b> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="27">proc <b class="cmd">practcl::_tagblock</b> <i class="arg">text</i> <span class="opt">?<i class="arg">style</i> <b class="const">tcl</b>?</span> <span class="opt">?<i class="arg">note</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="28">proc <b class="cmd">practcl::de_shell</b> <i class="arg">data</i></a></dt> <dd></dd> <dt><a name="29">proc <b class="cmd">practcl::cat</b> <i class="arg">fname</i></a></dt> <dd><p>Bits stolen from fileutil</p></dd> <dt><a name="30">proc <b class="cmd">practcl::grep</b> <i class="arg">pattern</i> <span class="opt">?<i class="arg">files</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="31">proc <b class="cmd">practcl::file_lexnormalize</b> <i class="arg">sp</i></a></dt> <dd></dd> <dt><a name="32">proc <b class="cmd">practcl::file_relative</b> <i class="arg">base</i> <i class="arg">dst</i></a></dt> <dd></dd> <dt><a name="33">proc <b class="cmd">practcl::log</b> <i class="arg">fname</i> <i class="arg">comment</i></a></dt> <dd></dd> <dt><a name="34">proc <b class="cmd">practcl::_isdirectory</b> <i class="arg">name</i></a></dt> <dd><p>Installer tools</p></dd> <dt><a name="35">proc <b class="cmd">practcl::_pkgindex_directory</b> <i class="arg">path</i></a></dt> <dd><p>Return true if the pkgindex file contains any statement other than "package ifneeded" and/or if any package ifneeded loads a DLL</p></dd> <dt><a name="36">proc <b class="cmd">practcl::_pkgindex_path_subdir</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="37">proc <b class="cmd">practcl::pkgindex_path</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Index all paths given as though they will end up in the same virtual file system</p></dd> <dt><a name="38">proc <b class="cmd">practcl::installDir</b> <i class="arg">d1</i> <i class="arg">d2</i></a></dt> <dd></dd> <dt><a name="39">proc <b class="cmd">practcl::copyDir</b> <i class="arg">d1</i> <i class="arg">d2</i> <span class="opt">?<i class="arg">toplevel</i> <b class="const">1</b>?</span></a></dt> <dd></dd> <dt><a name="40">proc <b class="cmd">practcl::trigger</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="41">proc <b class="cmd">practcl::depends</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="42">proc <b class="cmd">practcl::target</b> <i class="arg">name</i> <i class="arg">info</i> <span class="opt">?<i class="arg">action</i> <b class="const"></b>?</span></a></dt> <dd></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Classes</a></h2> <div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Class practcl::metaclass</a></h3> <p><em>ancestors</em>: <b class="class">oo::object</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="43">method <b class="cmd">_MorphPatterns</b></a></dt> <dd></dd> <dt><a name="44">method <b class="cmd">define</b> <i class="arg">submethod</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="45">method <b class="cmd">graft</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="46">method <b class="cmd">initialize</b></a></dt> <dd></dd> <dt><a name="47">method <b class="cmd">link</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="48">method <b class="cmd">morph</b> <i class="arg">classname</i></a></dt> <dd></dd> <dt><a name="49">method <b class="cmd">mixin</b> <i class="arg">slot</i> <i class="arg">classname</i></a></dt> <dd></dd> <dt><a name="50">method <b class="cmd">organ</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="51">method <b class="cmd">script</b> <i class="arg">script</i></a></dt> <dd></dd> <dt><a name="52">method <b class="cmd">select</b></a></dt> <dd></dd> <dt><a name="53">method <b class="cmd">source</b> <i class="arg">filename</i></a></dt> <dd></dd> </dl> </div> <div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">Class practcl::toolset</a></h3> <p>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</p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="54">method <b class="cmd">select</b> <i class="arg">object</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="55">method <b class="cmd">config.sh</b></a></dt> <dd><p>find or fake a key/value list describing this project</p></dd> <dt><a name="56">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd></dd> <dt><a name="57">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></dt> <dd></dd> <dt><a name="58">method <b class="cmd">read_configuration</b></a></dt> <dd></dd> <dt><a name="59">method <b class="cmd">build-cflags</b> <i class="arg">PROJECT</i> <i class="arg">DEFS</i> <i class="arg">namevar</i> <i class="arg">versionvar</i> <i class="arg">defsvar</i></a></dt> <dd><p>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</p></dd> <dt><a name="60">method <b class="cmd">critcl</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="61">method <b class="cmd">make-autodetect</b></a></dt> <dd></dd> </dl> </div> <div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Class practcl::toolset.gcc</a></h3> <p><em>ancestors</em>: <b class="class">practcl::toolset</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="62">method <b class="cmd">Autoconf</b></a></dt> <dd></dd> <dt><a name="63">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd></dd> <dt><a name="64">method <b class="cmd">ConfigureOpts</b></a></dt> <dd></dd> <dt><a name="65">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></dt> <dd><p>Detect what directory contains the Makefile template</p></dd> <dt><a name="66">method <b class="cmd">make-autodetect</b></a></dt> <dd></dd> <dt><a name="67">method <b class="cmd">make-clean</b></a></dt> <dd></dd> <dt><a name="68">method <b class="cmd">make-compile</b></a></dt> <dd></dd> <dt><a name="69">method <b class="cmd">make-install</b> <i class="arg">DEST</i></a></dt> <dd></dd> <dt><a name="70">method <b class="cmd">build-compile-sources</b> <i class="arg">PROJECT</i> <i class="arg">COMPILE</i> <i class="arg">CPPCOMPILE</i> <i class="arg">INCLUDES</i></a></dt> <dd></dd> <dt><a name="71">method <b class="cmd">build-Makefile</b> <i class="arg">path</i> <i class="arg">PROJECT</i></a></dt> <dd></dd> <dt><a name="72">method <b class="cmd">build-library</b> <i class="arg">outfile</i> <i class="arg">PROJECT</i></a></dt> <dd><p>Produce a static or dynamic library</p></dd> <dt><a name="73">method <b class="cmd">build-tclsh</b> <i class="arg">outfile</i> <i class="arg">PROJECT</i></a></dt> <dd><p>Produce a static executable</p></dd> </dl> </div> <div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Class practcl::toolset.msvc</a></h3> <p><em>ancestors</em>: <b class="class">practcl::toolset</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="74">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd><p>MSVC always builds in the source directory</p></dd> <dt><a name="75">method <b class="cmd">make-autodetect</b></a></dt> <dd><p>Do nothing</p></dd> <dt><a name="76">method <b class="cmd">make-clean</b></a></dt> <dd></dd> <dt><a name="77">method <b class="cmd">make-compile</b></a></dt> <dd></dd> <dt><a name="78">method <b class="cmd">make-install</b> <i class="arg">DEST</i></a></dt> <dd></dd> <dt><a name="79">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></dt> <dd><p>Detect what directory contains the Makefile template</p></dd> <dt><a name="80">method <b class="cmd">NmakeOpts</b></a></dt> <dd></dd> </dl> </div> <div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Class practcl::make_obj</a></h3> <p><em>ancestors</em>: <b class="class">practcl::metaclass</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="81">method <b class="cmd">constructor</b> <i class="arg">module_object</i> <i class="arg">name</i> <i class="arg">info</i> <span class="opt">?<i class="arg">action_body</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="82">method <b class="cmd">do</b></a></dt> <dd></dd> <dt><a name="83">method <b class="cmd">check</b></a></dt> <dd></dd> <dt><a name="84">method <b class="cmd">output</b></a></dt> <dd></dd> <dt><a name="85">method <b class="cmd">reset</b></a></dt> <dd></dd> <dt><a name="86">method <b class="cmd">triggers</b></a></dt> <dd></dd> </dl> </div> <div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Class practcl::object</a></h3> <p><em>ancestors</em>: <b class="class">practcl::metaclass</b></p> <p>A generic Practcl object</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="87">method <b class="cmd">constructor</b> <i class="arg">parent</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="88">method <b class="cmd">child</b> <i class="arg">method</i></a></dt> <dd></dd> <dt><a name="89">method <b class="cmd">go</b></a></dt> <dd></dd> </dl> </div> <div id="subsection7" class="doctools_subsection"><h3><a name="subsection7">Class practcl::dynamic</a></h3> <p>Dynamic blocks do not generate their own .c files, instead the contribute to the amalgamation of the main library file</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="90">method <b class="cmd">cstructure</b> <i class="arg">name</i> <i class="arg">definition</i> <span class="opt">?<i class="arg">argdat</i> <b class="const"></b>?</span></a></dt> <dd><p>Parser functions</p></dd> <dt><a name="91">method <b class="cmd">include</b> <i class="arg">header</i></a></dt> <dd></dd> <dt><a name="92">method <b class="cmd">include_dir</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="93">method <b class="cmd">include_directory</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="94">method <b class="cmd">c_header</b> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="95">method <b class="cmd">c_code</b> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="96">method <b class="cmd">c_function</b> <i class="arg">header</i> <i class="arg">body</i> <span class="opt">?<i class="arg">info</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="97">method <b class="cmd">c_tcloomethod</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="98">method <b class="cmd">cmethod</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></dt> <dd><p>Alias to classic name</p></dd> <dt><a name="99">method <b class="cmd">c_tclproc_nspace</b> <i class="arg">nspace</i></a></dt> <dd></dd> <dt><a name="100">method <b class="cmd">c_tclcmd</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="101">method <b class="cmd">c_tclproc_raw</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></dt> <dd><p>Alias to classic name</p></dd> <dt><a name="102">method <b class="cmd">tcltype</b> <i class="arg">name</i> <i class="arg">argdat</i></a></dt> <dd></dd> <dt><a name="103">method <b class="cmd">project-compile-products</b></a></dt> <dd><p>Module interactions</p></dd> <dt><a name="104">method <b class="cmd">implement</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="105">method <b class="cmd">initialize</b></a></dt> <dd><p>Practcl internals</p></dd> <dt><a name="106">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="107">method <b class="cmd">generate-cfile-constant</b></a></dt> <dd></dd> <dt><a name="108">method <b class="cmd">generate-cfile-header</b></a></dt> <dd></dd> <dt><a name="109">method <b class="cmd">generate-cfile-tclapi</b></a></dt> <dd><p>Generate code that provides implements Tcl API calls</p></dd> <dt><a name="110">method <b class="cmd">generate-loader-module</b></a></dt> <dd><p>Generate code that runs when the package/module is initialized into the interpreter</p></dd> <dt><a name="111">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></dt> <dd></dd> <dt><a name="112">method <b class="cmd">select</b></a></dt> <dd><p>Once an object marks itself as some flavor of dynamic, stop trying to morph it into something else</p></dd> </dl> </div> <div id="subsection8" class="doctools_subsection"><h3><a name="subsection8">Class practcl::product</a></h3> <p>A deliverable for the build system</p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="113">method <b class="cmd">select</b> <i class="arg">object</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="114">method <b class="cmd">code</b> <i class="arg">section</i> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="115">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></dt> <dd></dd> <dt><a name="116">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> <dt><a name="117">method <b class="cmd">generate-debug</b> <span class="opt">?<i class="arg">spaces</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="118">method <b class="cmd">generate-cfile-constant</b></a></dt> <dd></dd> <dt><a name="119">method <b class="cmd">generate-cfile-public-structure</b></a></dt> <dd><p>Populate const static data structures</p></dd> <dt><a name="120">method <b class="cmd">generate-cfile-header</b></a></dt> <dd></dd> <dt><a name="121">method <b class="cmd">generate-cfile-global</b></a></dt> <dd></dd> <dt><a name="122">method <b class="cmd">generate-cfile-private-typedef</b></a></dt> <dd></dd> <dt><a name="123">method <b class="cmd">generate-cfile-private-structure</b></a></dt> <dd></dd> <dt><a name="124">method <b class="cmd">generate-cfile-functions</b></a></dt> <dd><p>Generate code that provides subroutines called by Tcl API methods</p></dd> <dt><a name="125">method <b class="cmd">generate-cfile-tclapi</b></a></dt> <dd><p>Generate code that provides implements Tcl API calls</p></dd> <dt><a name="126">method <b class="cmd">generate-hfile-public-define</b></a></dt> <dd></dd> <dt><a name="127">method <b class="cmd">generate-hfile-public-macro</b></a></dt> <dd></dd> <dt><a name="128">method <b class="cmd">generate-hfile-public-typedef</b></a></dt> <dd></dd> <dt><a name="129">method <b class="cmd">generate-hfile-public-structure</b></a></dt> <dd></dd> <dt><a name="130">method <b class="cmd">generate-hfile-public-headers</b></a></dt> <dd></dd> <dt><a name="131">method <b class="cmd">generate-hfile-public-function</b></a></dt> <dd></dd> <dt><a name="132">method <b class="cmd">generate-hfile-public-includes</b></a></dt> <dd></dd> <dt><a name="133">method <b class="cmd">generate-hfile-public-verbatim</b></a></dt> <dd></dd> <dt><a name="134">method <b class="cmd">generate-loader-external</b></a></dt> <dd></dd> <dt><a name="135">method <b class="cmd">generate-loader-module</b></a></dt> <dd></dd> <dt><a name="136">method <b class="cmd">generate-stub-function</b></a></dt> <dd></dd> <dt><a name="137">method <b class="cmd">IncludeAdd</b> <i class="arg">headervar</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="138">method <b class="cmd">generate-tcl-loader</b></a></dt> <dd></dd> <dt><a name="139">method <b class="cmd">generate-tcl-pre</b></a></dt> <dd><p>This methods generates any Tcl script file which is required to pre-initialize the C library</p></dd> <dt><a name="140">method <b class="cmd">generate-tcl-post</b></a></dt> <dd></dd> <dt><a name="141">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="142">method <b class="cmd">Ofile</b> <i class="arg">filename</i></a></dt> <dd></dd> <dt><a name="143">method <b class="cmd">project-static-packages</b></a></dt> <dd><p>Methods called by the master project</p></dd> <dt><a name="144">method <b class="cmd">toolset-include-directory</b></a></dt> <dd><p>Methods called by the toolset</p></dd> <dt><a name="145">method <b class="cmd">target</b> <i class="arg">method</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection9" class="doctools_subsection"><h3><a name="subsection9">Class practcl::product.cheader</a></h3> <p><em>ancestors</em>: <b class="class">practcl::product</b></p> <p>Flesh out several trivial varieties of product</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="146">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> <dt><a name="147">method <b class="cmd">generate-loader-module</b></a></dt> <dd></dd> </dl> </div> <div id="subsection10" class="doctools_subsection"><h3><a name="subsection10">Class practcl::product.csource</a></h3> <p><em>ancestors</em>: <b class="class">practcl::product</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="148">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> </dl> </div> <div id="subsection11" class="doctools_subsection"><h3><a name="subsection11">Class practcl::product.clibrary</a></h3> <p><em>ancestors</em>: <b class="class">practcl::product</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="149">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></dt> <dd></dd> </dl> </div> <div id="subsection12" class="doctools_subsection"><h3><a name="subsection12">Class practcl::product.dynamic</a></h3> <p><em>ancestors</em>: <b class="class">practcl::dynamic</b> <b class="class">practcl::product</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="150">method <b class="cmd">initialize</b></a></dt> <dd></dd> </dl> </div> <div id="subsection13" class="doctools_subsection"><h3><a name="subsection13">Class practcl::product.critcl</a></h3> <p><em>ancestors</em>: <b class="class">practcl::dynamic</b> <b class="class">practcl::product</b></p> </div> <div id="subsection14" class="doctools_subsection"><h3><a name="subsection14">Class practcl::module</a></h3> <p><em>ancestors</em>: <b class="class">practcl::object</b> <b class="class">practcl::product.dynamic</b></p> <p>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</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="151">method <b class="cmd">_MorphPatterns</b></a></dt> <dd></dd> <dt><a name="152">method <b class="cmd">add</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="153">method <b class="cmd">install-headers</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="154">method <b class="cmd">make</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Target handling</p></dd> <dt><a name="155">method <b class="cmd">child</b> <i class="arg">which</i></a></dt> <dd></dd> <dt><a name="156">method <b class="cmd">generate-c</b></a></dt> <dd><p>This methods generates the contents of an amalgamated .c file which implements the loader for a batch of tools</p></dd> <dt><a name="157">method <b class="cmd">generate-h</b></a></dt> <dd><p>This methods generates the contents of an amalgamated .h file which describes the public API of this module</p></dd> <dt><a name="158">method <b class="cmd">generate-loader</b></a></dt> <dd></dd> <dt><a name="159">method <b class="cmd">initialize</b></a></dt> <dd></dd> <dt><a name="160">method <b class="cmd">implement</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="161">method <b class="cmd">linktype</b></a></dt> <dd></dd> </dl> </div> <div id="subsection15" class="doctools_subsection"><h3><a name="subsection15">Class practcl::project</a></h3> <p><em>ancestors</em>: <b class="class">practcl::module</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="162">method <b class="cmd">_MorphPatterns</b></a></dt> <dd></dd> <dt><a name="163">method <b class="cmd">constructor</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="164">method <b class="cmd">add_object</b> <i class="arg">object</i></a></dt> <dd></dd> <dt><a name="165">method <b class="cmd">add_project</b> <i class="arg">pkg</i> <i class="arg">info</i> <span class="opt">?<i class="arg">oodefine</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="166">method <b class="cmd">add_tool</b> <i class="arg">pkg</i> <i class="arg">info</i> <span class="opt">?<i class="arg">oodefine</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="167">method <b class="cmd">build-tclcore</b></a></dt> <dd></dd> <dt><a name="168">method <b class="cmd">child</b> <i class="arg">which</i></a></dt> <dd></dd> <dt><a name="169">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="170">method <b class="cmd">project</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Exercise the methods of a sub-object</p></dd> <dt><a name="171">method <b class="cmd">tclcore</b></a></dt> <dd></dd> <dt><a name="172">method <b class="cmd">tkcore</b></a></dt> <dd></dd> <dt><a name="173">method <b class="cmd">tool</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection16" class="doctools_subsection"><h3><a name="subsection16">Class practcl::library</a></h3> <p><em>ancestors</em>: <b class="class">practcl::project</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="174">method <b class="cmd">clean</b> <i class="arg">PATH</i></a></dt> <dd></dd> <dt><a name="175">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> <dt><a name="176">method <b class="cmd">go</b></a></dt> <dd></dd> <dt><a name="177">method <b class="cmd">generate-decls</b> <i class="arg">pkgname</i> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="178">method <b class="cmd">implement</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="179">method <b class="cmd">generate-make</b> <i class="arg">path</i></a></dt> <dd><p>Backward compadible call</p></dd> <dt><a name="180">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="181">method <b class="cmd">package-ifneeded</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Create a "package ifneeded" Args are a list of aliases for which this package will answer to</p></dd> <dt><a name="182">method <b class="cmd">shared_library</b> <span class="opt">?<i class="arg">filename</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="183">method <b class="cmd">static_library</b> <span class="opt">?<i class="arg">filename</i> <b class="const"></b>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection17" class="doctools_subsection"><h3><a name="subsection17">Class practcl::tclkit</a></h3> <p><em>ancestors</em>: <b class="class">practcl::library</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="184">method <b class="cmd">build-tclkit_main</b> <i class="arg">PROJECT</i> <i class="arg">PKG_OBJS</i></a></dt> <dd></dd> <dt><a name="185">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></dt> <dd></dd> <dt><a name="186">method <b class="cmd">wrap</b> <i class="arg">PWD</i> <i class="arg">exename</i> <i class="arg">vfspath</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Wrap an executable</p></dd> </dl> </div> <div id="subsection18" class="doctools_subsection"><h3><a name="subsection18">Class practcl::distribution</a></h3> <p>Standalone class to manage code distribution This class is intended to be mixed into another class (Thus the lack of ancestors)</p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="187">method <b class="cmd">Sandbox</b> <i class="arg">object</i></a></dt> <dd></dd> <dt><a name="188">method <b class="cmd">select</b> <i class="arg">object</i></a></dt> <dd></dd> <dt><a name="189">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="190">method <b class="cmd">claim_object</b> <i class="arg">object</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="191">method <b class="cmd">scm_info</b></a></dt> <dd></dd> <dt><a name="192">method <b class="cmd">DistroMixIn</b></a></dt> <dd></dd> <dt><a name="193">method <b class="cmd">Sandbox</b></a></dt> <dd></dd> <dt><a name="194">method <b class="cmd">SrcDir</b></a></dt> <dd></dd> <dt><a name="195">method <b class="cmd">ScmTag</b></a></dt> <dd></dd> <dt><a name="196">method <b class="cmd">ScmClone</b></a></dt> <dd></dd> <dt><a name="197">method <b class="cmd">ScmUnpack</b></a></dt> <dd></dd> <dt><a name="198">method <b class="cmd">ScmUpdate</b></a></dt> <dd></dd> <dt><a name="199">method <b class="cmd">Unpack</b></a></dt> <dd></dd> </dl> </div> <div id="subsection19" class="doctools_subsection"><h3><a name="subsection19">Class practcl::distribution.snapshot</a></h3> <p><em>ancestors</em>: <b class="class">practcl::distribution</b></p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="200">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="201">method <b class="cmd">claim_object</b> <i class="arg">object</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="202">method <b class="cmd">ScmUnpack</b></a></dt> <dd></dd> </dl> </div> <div id="subsection20" class="doctools_subsection"><h3><a name="subsection20">Class practcl::distribution.fossil</a></h3> <p><em>ancestors</em>: <b class="class">practcl::distribution</b></p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="203">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></dt> <dd><p>Check for markers in the source root</p></dd> <dt><a name="204">method <b class="cmd">claim_object</b> <i class="arg">obj</i></a></dt> <dd><p>Check for markers in the metadata</p></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="205">method <b class="cmd">scm_info</b></a></dt> <dd></dd> <dt><a name="206">method <b class="cmd">ScmClone</b></a></dt> <dd><p>Clone the source</p></dd> <dt><a name="207">method <b class="cmd">ScmTag</b></a></dt> <dd></dd> <dt><a name="208">method <b class="cmd">ScmUnpack</b></a></dt> <dd></dd> <dt><a name="209">method <b class="cmd">ScmUpdate</b></a></dt> <dd></dd> </dl> </div> <div id="subsection21" class="doctools_subsection"><h3><a name="subsection21">Class practcl::distribution.git</a></h3> <p><em>ancestors</em>: <b class="class">practcl::distribution</b></p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="210">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="211">method <b class="cmd">claim_object</b> <i class="arg">obj</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="212">method <b class="cmd">ScmTag</b></a></dt> <dd></dd> <dt><a name="213">method <b class="cmd">ScmUnpack</b></a></dt> <dd></dd> <dt><a name="214">method <b class="cmd">ScmUpdate</b></a></dt> <dd></dd> </dl> </div> <div id="subsection22" class="doctools_subsection"><h3><a name="subsection22">Class practcl::subproject</a></h3> <p><em>ancestors</em>: <b class="class">practcl::module</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="215">method <b class="cmd">_MorphPatterns</b></a></dt> <dd></dd> <dt><a name="216">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd></dd> <dt><a name="217">method <b class="cmd">child</b> <i class="arg">which</i></a></dt> <dd></dd> <dt><a name="218">method <b class="cmd">compile</b></a></dt> <dd></dd> <dt><a name="219">method <b class="cmd">go</b></a></dt> <dd></dd> <dt><a name="220">method <b class="cmd">install</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Install project into the local build system</p></dd> <dt><a name="221">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="222">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></dt> <dd></dd> <dt><a name="223">method <b class="cmd">linker-external</b> <i class="arg">configdict</i></a></dt> <dd></dd> <dt><a name="224">method <b class="cmd">linker-extra</b> <i class="arg">configdict</i></a></dt> <dd></dd> <dt><a name="225">method <b class="cmd">env-bootstrap</b></a></dt> <dd><p>Methods for packages/tools that can be downloaded possibly built and used internally by this Practcl process Load the facility into the interpreter</p></dd> <dt><a name="226">method <b class="cmd">env-exec</b></a></dt> <dd><p>Return a file path that exec can call</p></dd> <dt><a name="227">method <b class="cmd">env-install</b></a></dt> <dd><p>Install the tool into the local environment</p></dd> <dt><a name="228">method <b class="cmd">env-load</b></a></dt> <dd><p>Do whatever is necessary to get the tool into the local environment</p></dd> <dt><a name="229">method <b class="cmd">env-present</b></a></dt> <dd><p>Check if tool is available for load/already loaded</p></dd> <dt><a name="230">method <b class="cmd">sources</b></a></dt> <dd></dd> <dt><a name="231">method <b class="cmd">update</b></a></dt> <dd></dd> <dt><a name="232">method <b class="cmd">unpack</b></a></dt> <dd></dd> </dl> </div> <div id="subsection23" class="doctools_subsection"><h3><a name="subsection23">Class practcl::subproject.source</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b> <b class="class">practcl::library</b></p> <p>A project which the kit compiles and integrates the source for itself</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="233">method <b class="cmd">env-bootstrap</b></a></dt> <dd></dd> <dt><a name="234">method <b class="cmd">env-present</b></a></dt> <dd></dd> <dt><a name="235">method <b class="cmd">linktype</b></a></dt> <dd></dd> </dl> </div> <div id="subsection24" class="doctools_subsection"><h3><a name="subsection24">Class practcl::subproject.teapot</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p>a copy from the teapot</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="236">method <b class="cmd">env-bootstrap</b></a></dt> <dd></dd> <dt><a name="237">method <b class="cmd">env-install</b></a></dt> <dd></dd> <dt><a name="238">method <b class="cmd">env-present</b></a></dt> <dd></dd> <dt><a name="239">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection25" class="doctools_subsection"><h3><a name="subsection25">Class practcl::subproject.kettle</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="240">method <b class="cmd">kettle</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="241">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection26" class="doctools_subsection"><h3><a name="subsection26">Class practcl::subproject.critcl</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="242">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection27" class="doctools_subsection"><h3><a name="subsection27">Class practcl::subproject.sak</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="243">method <b class="cmd">env-bootstrap</b></a></dt> <dd></dd> <dt><a name="244">method <b class="cmd">env-install</b></a></dt> <dd></dd> <dt><a name="245">method <b class="cmd">env-present</b></a></dt> <dd></dd> <dt><a name="246">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> <dt><a name="247">method <b class="cmd">install-module</b> <i class="arg">DEST</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection28" class="doctools_subsection"><h3><a name="subsection28">Class practcl::subproject.binary</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p>A binary package</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="248">method <b class="cmd">clean</b></a></dt> <dd></dd> <dt><a name="249">method <b class="cmd">env-install</b></a></dt> <dd></dd> <dt><a name="250">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> <dt><a name="251">method <b class="cmd">ComputeInstall</b></a></dt> <dd></dd> <dt><a name="252">method <b class="cmd">go</b></a></dt> <dd></dd> <dt><a name="253">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></dt> <dd></dd> <dt><a name="254">method <b class="cmd">project-static-packages</b></a></dt> <dd></dd> <dt><a name="255">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd></dd> <dt><a name="256">method <b class="cmd">compile</b></a></dt> <dd></dd> <dt><a name="257">method <b class="cmd">Configure</b></a></dt> <dd></dd> <dt><a name="258">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection29" class="doctools_subsection"><h3><a name="subsection29">Class practcl::subproject.tea</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject.binary</b></p> </div> <div id="subsection30" class="doctools_subsection"><h3><a name="subsection30">Class practcl::subproject.library</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject.binary</b> <b class="class">practcl::library</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="259">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection31" class="doctools_subsection"><h3><a name="subsection31">Class practcl::subproject.external</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject.binary</b></p> <p>An external library</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="260">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection32" class="doctools_subsection"><h3><a name="subsection32">Class practcl::subproject.core</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject.binary</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="261">method <b class="cmd">env-bootstrap</b></a></dt> <dd></dd> <dt><a name="262">method <b class="cmd">env-present</b></a></dt> <dd></dd> <dt><a name="263">method <b class="cmd">env-install</b></a></dt> <dd></dd> <dt><a name="264">method <b class="cmd">go</b></a></dt> <dd></dd> <dt><a name="265">method <b class="cmd">linktype</b></a></dt> <dd></dd> </dl> </div> </div> <div id="section4" class="doctools_section"><h2><a name="section4">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>practcl</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. Please also report any ideas for enhancements you may have for either package and/or documentation.</p> <p>When proposing code changes, please provide <em>unified diffs</em>, i.e the output of <b class="const">diff -u</b>.</p> <p>Note further that <em>attachments</em> are strongly preferred over inlined patches. Attachments can be made by going to the <b class="const">Edit</b> form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p>practcl</p> </div> <div id="category" class="doctools_section"><h2><a name="category">Category</a></h2> <p>TclOO</p> </div> <div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> <p>Copyright © 2016-2018 Sean Woods <[email protected]></p> </div> </div></body></html> |
Changes to embedded/www/tcllib/files/modules/pt/pt_peg_op.html.
︙ | ︙ | |||
95 96 97 98 99 100 101 | | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> | | | | 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 | | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> <h1 class="doctools_title">pt_peg_op(i) 1.0.2 tcllib "Parser Tools"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>pt_peg_op - Parser Tools PE Grammar Utility Operations</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">API</a></li> <li class="doctools_section"><a href="#section3">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.5</b></li> <li>package require <b class="pkgname">pt::peg::op <span class="opt">?1.0.2?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">::peg::peg::op</b> <b class="method">called</b> <i class="arg">container</i></a></li> <li><a href="#2"><b class="cmd">::peg::peg::op</b> <b class="method">dechain</b> <i class="arg">container</i></a></li> <li><a href="#3"><b class="cmd">::peg::peg::op</b> <b class="method">drop unreachable</b> <i class="arg">container</i></a></li> <li><a href="#4"><b class="cmd">::peg::peg::op</b> <b class="method">drop unrealizable</b> <i class="arg">container</i></a></li> <li><a href="#5"><b class="cmd">::peg::peg::op</b> <b class="method">flatten</b> <i class="arg">container</i></a></li> |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/smtpd/smtpd.html.
︙ | ︙ | |||
287 288 289 290 291 292 293 | <p>The content of any error message will not be passed back to the client.</p></dd> <dt><b class="cmd">validate_recipient</b> callback</dt> <dd><p>The validate_recipient callback is similar to the validate_sender callback and permits you to verify a local mailbox and accept mail for a local user address during RCPT command handling. To reject mail, throw an error as above. The error message is ignored.</p></dd> <dt><b class="cmd">deliverMIME</b> callback</dt> | < | | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | <p>The content of any error message will not be passed back to the client.</p></dd> <dt><b class="cmd">validate_recipient</b> callback</dt> <dd><p>The validate_recipient callback is similar to the validate_sender callback and permits you to verify a local mailbox and accept mail for a local user address during RCPT command handling. To reject mail, throw an error as above. The error message is ignored.</p></dd> <dt><b class="cmd">deliverMIME</b> callback</dt> <dd><p>The deliverMIME callback is called once a mail message has been successfully passed to the server. A mime token is constructed from the sender, recipients and data and the users procedure it called with this single argument. When the call returns, the mime token is cleaned up so if the user wishes to preserve the data she must make a copy.</p> <pre class="doctools_example"> proc deliverMIME {token} { set sender [lindex [mime::getheader $token From] 0] |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/stooop/switched.html.
︙ | ︙ | |||
305 306 307 308 309 310 311 | listed in the <b class="method">options</b> procedure) but obviously does not check the validity of the value passed to the <b class="method">set-<b class="option">option</b></b> procedure, which should throw an error (for example by using the Tcl error command) if the value is invalid.</p> <p>The switched layer also keeps track of the options current values, so that a <b class="method">set-<b class="option">option</b></b> procedure is called only when the corresponding option value passed as parameter is | | | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | listed in the <b class="method">options</b> procedure) but obviously does not check the validity of the value passed to the <b class="method">set-<b class="option">option</b></b> procedure, which should throw an error (for example by using the Tcl error command) if the value is invalid.</p> <p>The switched layer also keeps track of the options current values, so that a <b class="method">set-<b class="option">option</b></b> procedure is called only when the corresponding option value passed as parameter is different from the current value (see <b class="variable">-option</b> data members description).</p></dd> <dt><b class="variable">-option</b></dt> <dd><p>The <b class="variable">-option</b> data member is an options current value. There is one for each option listed in the options procedure. It is a read-only value which the switched layer checks against when an option is changed. It is rarely used at the layer derived from switched, except in the few cases, such as in the following example:</p> <pre class="doctools_example"> ... |
︙ | ︙ | |||
332 333 334 335 336 337 338 | puts "manufacturer: $switched::($this,-manufacturer)" ... } </pre> <p>In this case, the manufacturer's name is stored at the switched layer level (this is why the set-manufacturer procedure has nothing to do) and later retrieved in the printData procedure.</p></dd> | | | | | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | puts "manufacturer: $switched::($this,-manufacturer)" ... } </pre> <p>In this case, the manufacturer's name is stored at the switched layer level (this is why the set-manufacturer procedure has nothing to do) and later retrieved in the printData procedure.</p></dd> <dt><b class="variable">complete</b></dt> <dd><p>The <b class="variable">complete</b> data member (not to be confused with the <b class="method">complete</b> procedure) is a boolean. Its initial value is <b class="const">false</b> and it is set to <b class="const">true</b> at the very end of the switched <b class="method">complete</b> procedure. It becomes useful when some options should be set at construction time only and not dynamically, as the following example shows:</p> <pre class="doctools_example"> proc car::set-width {this value} { if {$switched::($this,complete)} { |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/tepam/tepam_doc_gen.html.
︙ | ︙ | |||
315 316 317 318 319 320 321 | <dd><p>Generates the part of the command line or the synopsis that is specific to an argument. The generated string has to indicate if an argument is optional, named and if it is a flag.</p> <p>The following parameters are provided to this procedure:</p> <dl class="doctools_definitions"> <dt><i class="arg">Name</i></dt> <dd><p>Name of the argument</p></dd> <dt><i class="arg">IsOptional</i></dt> | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | <dd><p>Generates the part of the command line or the synopsis that is specific to an argument. The generated string has to indicate if an argument is optional, named and if it is a flag.</p> <p>The following parameters are provided to this procedure:</p> <dl class="doctools_definitions"> <dt><i class="arg">Name</i></dt> <dd><p>Name of the argument</p></dd> <dt><i class="arg">IsOptional</i></dt> <dd><p>If true (=<b class="const">1</b>) the argument is optional which should be indicated by the generated string (for example by putting the argument into brackets {[]} or into question marks '?'):</p> <pre class="doctools_example">gen(TXT,ArgumentString) mtype 1 0 string -> <em>"[mtype]"</em></pre> </dd> <dt><i class="arg">IsNamed</i></dt> <dd><p>If true (=<b class="const">1</b>) an argument is a named argument (option). The generated string should in this case contain the argument/option name, followed by the argument itself:</p> <pre class="doctools_example">gen(TXT,ArgumentString) mtype 0 1 string -> <em>"-mtype <mtype>"</em></pre> <p>Named arguments can also be optional:</p> <pre class="doctools_example">gen(TXT,ArgumentString) mtype 1 1 string -> <em>"[-mtype <mtype>]"</em></pre> |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/tepam/tepam_procedure.html.
︙ | ︙ | |||
706 707 708 709 710 711 712 | <p>Named arguments can be defined multiple times. If the named argument has the <em>-multiply</em> attribute, all argument values will be collected in a list. Otherwise, only the last provided attribute value will be retained:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 -n1 M1 U1 U2</b> <em>-> n1:'M1', n2:'N2', u1:'U1', u2:'U2'</em></pre> <p>The name of the first unnamed argument has therefore not to start with the '-' character. The unnamed argument is otherwise considered as name of another named argument. This is especially important if the first unnamed argument is given by a variable that can contain any character strings:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 "->" "<-"</b> <em>-> my_proc: Argument '->' not known</em> set U1 "->" | | | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | <p>Named arguments can be defined multiple times. If the named argument has the <em>-multiply</em> attribute, all argument values will be collected in a list. Otherwise, only the last provided attribute value will be retained:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 -n1 M1 U1 U2</b> <em>-> n1:'M1', n2:'N2', u1:'U1', u2:'U2'</em></pre> <p>The name of the first unnamed argument has therefore not to start with the '-' character. The unnamed argument is otherwise considered as name of another named argument. This is especially important if the first unnamed argument is given by a variable that can contain any character strings:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 "->" "<-"</b> <em>-> my_proc: Argument '->' not known</em> set U1 "->" my_proc <b class="cmd">-n1 N1 -n2 N2 $U1 U2</b> my_proc: Argument '->' not known</pre> <p>The '--' flag allows separating unambiguously the unnamed arguments from the named arguments. All data after the '--' flag will be considered as unnamed argument:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 -- "->" "<-"</b> <em>-> n1:'N1', n2:'N2', u1:'->', u2:'<-'</em> set U1 "->" my_proc <b class="cmd">-n1 N1 -n2 N2 -- $U1 U2</b> <em>-> n1:'N1', n2:'N2', u1:'->', u2:'<-'</em></pre> |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/textutil/adjust.html.
︙ | ︙ | |||
199 200 201 202 203 204 205 | there are no space chars at the end of this line, and there may be some space chars at the beginning, despite of the <b class="option">-full</b> option.</p></dd> </dl></dd> <dt><b class="option">-length</b> <i class="arg">integer</i></dt> <dd><p>Set the length of the <em>logical</em> line in the string to <i class="arg">integer</i>. <i class="arg">integer</i> must be a positive integer value. Defaults to <b class="const">72</b>.</p></dd> | | < | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | there are no space chars at the end of this line, and there may be some space chars at the beginning, despite of the <b class="option">-full</b> option.</p></dd> </dl></dd> <dt><b class="option">-length</b> <i class="arg">integer</i></dt> <dd><p>Set the length of the <em>logical</em> line in the string to <i class="arg">integer</i>. <i class="arg">integer</i> must be a positive integer value. Defaults to <b class="const">72</b>.</p></dd> <dt><b class="option">-strictlength</b> <i class="arg">boolean</i></dt> <dd><p>If set to <b class="const">false</b> (default), a line can exceed the specified <b class="option">-length</b> if a single word is longer than <b class="option">-length</b>. If set to <b class="const">true</b>, words that are longer than <b class="option">-length</b> are split so that no line exceeds the specified <b class="option">-length</b>.</p></dd> </dl></dd> <dt><a name="2"><b class="cmd">::textutil::adjust::readPatterns</b> <i class="arg">filename</i></a></dt> <dd><p>Loads the internal storage for hyphenation patterns with the contents of the file <i class="arg">filename</i>. This has to be done prior to calling |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/tool/tool_dict_ensemble.html.
︙ | ︙ | |||
117 118 119 120 121 122 123 | </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">tool <span class="opt">?0.4.2?</span></b></li> </ul> <ul class="doctools_syntax"> | | | < | | 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 | </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">tool <span class="opt">?0.4.2?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><em>object</em> <i class="arg">ensemble</i> <b class="cmd">add</b> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">value ...</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>The <b class="cmd">dict_ensemble</b> command is a keyword added by <b class="package"><a href="tool.html">tool</a></b>. It defines a public variable (stored as a dict), and an access function to manipulated and access the values stored in that dict.</p> <dl class="doctools_definitions"> <dt><a name="1"><em>object</em> <i class="arg">ensemble</i> <b class="cmd">add</b> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">value ...</i></a></dt> <dd><p>Adds elements to a list maintained with the <i class="arg">field</i> leaf of the dict maintained my this ensemble. Declares a variable <i class="arg">name</i> which will be initialized as an array, populated with <i class="arg">contents</i> for objects of this class, as well as any objects for classes which are descendents of this class.</p></dd> </dl> </div> <div id="section2" class="doctools_section"><h2><a name="section2">AUTHORS</a></h2> <p>Sean Woods</p> |
︙ | ︙ |
Changes to embedded/www/tcllib/files/modules/websocket/websocket.html.
︙ | ︙ | |||
283 284 285 286 287 288 289 | <dt><a name="3"><b class="cmd">::websocket::server</b> <i class="arg">sock</i></a></dt> <dd><p>This command registers the (accept) socket <i class="arg">sock</i> as the identifier fo an HTTP server that is capable of doing WebSockets. Paths onto which this server will listen for incoming connections should be declared using <b class="cmd">::websocket::live</b>.</p></dd> <dt><a name="4"><b class="cmd">::websocket::live</b> <i class="arg">sock</i> <i class="arg">path</i> <i class="arg">cb</i> <span class="opt">?<i class="arg">proto</i>?</span></a></dt> <dd><p>This procedure registers callbacks that will be performed on a | | | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | <dt><a name="3"><b class="cmd">::websocket::server</b> <i class="arg">sock</i></a></dt> <dd><p>This command registers the (accept) socket <i class="arg">sock</i> as the identifier fo an HTTP server that is capable of doing WebSockets. Paths onto which this server will listen for incoming connections should be declared using <b class="cmd">::websocket::live</b>.</p></dd> <dt><a name="4"><b class="cmd">::websocket::live</b> <i class="arg">sock</i> <i class="arg">path</i> <i class="arg">cb</i> <span class="opt">?<i class="arg">proto</i>?</span></a></dt> <dd><p>This procedure registers callbacks that will be performed on a WebSocket compliant server registered with <b class="cmd">::websocket::server</b> whenever a client connects to a matching path and protocol. <i class="arg">sock</i> is the listening socket of the websocket compliant server declared using <b class="cmd">::websocket::server</b>. <i class="arg">path</i> is a glob-style path to match in client request, whenever this will occur. <i class="arg">cb</i> is the command to callback (see Callbacks). <i class="arg">proto</i> is a glob-style protocol name matcher.</p></dd> <dt><a name="5"><b class="cmd">::websocket::test</b> <i class="arg">srvSock</i> <i class="arg">cliSock</i> <i class="arg">path</i> <span class="opt">?<i class="arg">hdrs</i>?</span> <span class="opt">?<i class="arg">qry</i>?</span></a></dt> |
︙ | ︙ |
Changes to embedded/www/tcllib/toc.html.
︙ | ︙ | |||
847 848 849 850 851 852 853 854 855 856 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='md4'><a href="files/modules/md4/md4.html">md4</a></td> <td class="#doctools_tocright">MD4 Message-Digest Algorithm</td> </tr> | > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 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 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='md4'><a href="files/modules/md4/md4.html">md4</a></td> <td class="#doctools_tocright">MD4 Message-Digest Algorithm</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='md5'><a href="files/modules/md5/md5.html">md5</a></td> <td class="#doctools_tocright">MD5 Message-Digest Algorithm</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='md5crypt'><a href="files/modules/md5crypt/md5crypt.html">md5crypt</a></td> <td class="#doctools_tocright">MD5-based password encryption</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='mime'><a href="files/modules/mime/mime.html">mime</a></td> <td class="#doctools_tocright">Manipulation of MIME body parts</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='mpexpand'><a href="files/modules/doctools/mpexpand.html">mpexpand</a></td> <td class="#doctools_tocright">Markup processor</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='multiplexer'><a href="files/modules/multiplexer/multiplexer.html">multiplexer</a></td> <td class="#doctools_tocright">One-to-many communication with sockets.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nameserv'><a href="files/modules/nns/nns_client.html">nameserv</a></td> <td class="#doctools_tocright">Name service facility, Client</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nameserv_auto'><a href="files/modules/nns/nns_auto.html">nameserv::auto</a></td> <td class="#doctools_tocright">Name service facility, Client Extension</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nameserv_common'><a href="files/modules/nns/nns_common.html">nameserv::common</a></td> <td class="#doctools_tocright">Name service facility, shared definitions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nameserv_protocol'><a href="files/modules/nns/nns_protocol.html">nameserv::protocol</a></td> <td class="#doctools_tocright">Name service facility, client/server protocol</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nameserv_server'><a href="files/modules/nns/nns_server.html">nameserv::server</a></td> <td class="#doctools_tocright">Name service facility, Server</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='namespacex'><a href="files/modules/namespacex/namespacex.html">namespacex</a></td> <td class="#doctools_tocright">Namespace utility commands</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='ncgi'><a href="files/modules/ncgi/ncgi.html">ncgi</a></td> <td class="#doctools_tocright">Procedures to manipulate CGI values.</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nettool'><a href="files/modules/nettool/nettool.html">nettool</a></td> <td class="#doctools_tocright">Tools for networked applications</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nmea'><a href="files/modules/nmea/nmea.html">nmea</a></td> <td class="#doctools_tocright">Process NMEA data</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nns'><a href="files/apps/nns.html">nns</a></td> <td class="#doctools_tocright">Name service facility, Commandline Client Application</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nns_intro'><a href="files/modules/nns/nns_intro.html">nns_intro</a></td> <td class="#doctools_tocright">Name service facility, introduction</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nnsd'><a href="files/apps/nnsd.html">nnsd</a></td> <td class="#doctools_tocright">Name service facility, Commandline Server Application</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nnslog'><a href="files/apps/nnslog.html">nnslog</a></td> <td class="#doctools_tocright">Name service facility, Commandline Logging Client Application</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nntp'><a href="files/modules/nntp/nntp.html">nntp</a></td> <td class="#doctools_tocright">Tcl client for the NNTP protocol</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='ntp_time'><a href="files/modules/ntp/ntp_time.html">ntp_time</a></td> <td class="#doctools_tocright">Tcl Time Service Client</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='oauth'><a href="files/modules/oauth/oauth.html">oauth</a></td> <td class="#doctools_tocright">oauth API base signature</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='oo_util'><a href="files/modules/tool/meta.html">oo::util</a></td> <td class="#doctools_tocright">Utility commands for TclOO</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='oo_util'><a href="files/modules/ooutil/ooutil.html">oo::util</a></td> <td class="#doctools_tocright">Utility commands for TclOO</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='oometa'><a href="files/modules/oometa/oometa.html">oometa</a></td> <td class="#doctools_tocright">oo::meta A data registry for classess</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='otp'><a href="files/modules/otp/otp.html">otp</a></td> <td class="#doctools_tocright">One-Time Passwords</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='page'><a href="files/apps/page.html">page</a></td> <td class="#doctools_tocright">Parser Generator</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='page_intro'><a href="files/modules/page/page_intro.html">page_intro</a></td> <td class="#doctools_tocright">page introduction</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='page_pluginmgr'><a href="files/modules/page/page_pluginmgr.html">page_pluginmgr</a></td> <td class="#doctools_tocright">page plugin manager</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='page_util_flow'><a href="files/modules/page/page_util_flow.html">page_util_flow</a></td> <td class="#doctools_tocright">page dataflow/treewalker utility</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='page_util_norm_lemon'><a href="files/modules/page/page_util_norm_lemon.html">page_util_norm_lemon</a></td> <td class="#doctools_tocright">page AST normalization, LEMON</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='page_util_norm_peg'><a href="files/modules/page/page_util_norm_peg.html">page_util_norm_peg</a></td> <td class="#doctools_tocright">page AST normalization, PEG</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='page_util_peg'><a href="files/modules/page/page_util_peg.html">page_util_peg</a></td> <td class="#doctools_tocright">page PEG transformation utilities</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='page_util_quote'><a href="files/modules/page/page_util_quote.html">page_util_quote</a></td> <td class="#doctools_tocright">page character quoting utilities</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='picoirc'><a href="files/modules/irc/picoirc.html">picoirc</a></td> <td class="#doctools_tocright">Small and simple embeddable IRC client.</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pki'><a href="files/modules/pki/pki.html">pki</a></td> <td class="#doctools_tocright">Implementation of the public key cipher</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pluginmgr'><a href="files/modules/pluginmgr/pluginmgr.html">pluginmgr</a></td> <td class="#doctools_tocright">Manage a plugin</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='png'><a href="files/modules/png/png.html">png</a></td> <td class="#doctools_tocright">PNG querying and manipulation of meta data</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pop3'><a href="files/modules/pop3/pop3.html">pop3</a></td> <td class="#doctools_tocright">Tcl client for POP3 email protocol</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pop3d'><a href="files/modules/pop3d/pop3d.html">pop3d</a></td> <td class="#doctools_tocright">Tcl POP3 server implementation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pop3d_dbox'><a href="files/modules/pop3d/pop3d_dbox.html">pop3d::dbox</a></td> <td class="#doctools_tocright">Simple mailbox database for pop3d</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pop3d_udb'><a href="files/modules/pop3d/pop3d_udb.html">pop3d::udb</a></td> <td class="#doctools_tocright">Simple user database for pop3d</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='practcl'><a href="files/modules/practcl/practcl.html">practcl</a></td> <td class="#doctools_tocright">The Practcl Module</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='processman'><a href="files/modules/processman/processman.html">processman</a></td> <td class="#doctools_tocright">Tool for automating the period callback of commands</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='profiler'><a href="files/modules/profiler/profiler.html">profiler</a></td> <td class="#doctools_tocright">Tcl source code profiler</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt'><a href="files/apps/pt.html">pt</a></td> <td class="#doctools_tocright">Parser Tools Application</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_ast'><a href="files/modules/pt/pt_astree.html">pt::ast</a></td> <td class="#doctools_tocright">Abstract Syntax Tree Serialization</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_cparam_configuration_critcl'><a href="files/modules/pt/pt_cparam_config_critcl.html">pt::cparam::configuration::critcl</a></td> <td class="#doctools_tocright">C/PARAM, Canned configuration, Critcl</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_cparam_configuration_tea'><a href="files/modules/pt/pt_cparam_config_tea.html">pt::cparam::configuration::tea</a></td> <td class="#doctools_tocright">C/PARAM, Canned configuration, TEA</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_json_language'><a href="files/modules/pt/pt_json_language.html">pt::json_language</a></td> <td class="#doctools_tocright">The JSON Grammar Exchange Format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_param'><a href="files/modules/pt/pt_param.html">pt::param</a></td> <td class="#doctools_tocright">PackRat Machine Specification</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_pe'><a href="files/modules/pt/pt_pexpression.html">pt::pe</a></td> <td class="#doctools_tocright">Parsing Expression Serialization</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_pe_op'><a href="files/modules/pt/pt_pexpr_op.html">pt::pe::op</a></td> <td class="#doctools_tocright">Parsing Expression Utilities</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg'><a href="files/modules/pt/pt_pegrammar.html">pt::peg</a></td> <td class="#doctools_tocright">Parsing Expression Grammar Serialization</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_container'><a href="files/modules/pt/pt_peg_container.html">pt::peg::container</a></td> <td class="#doctools_tocright">PEG Storage</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_container_peg'><a href="files/modules/pt/pt_peg_container_peg.html">pt::peg::container::peg</a></td> <td class="#doctools_tocright">PEG Storage. Canned PEG grammar specification</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_export'><a href="files/modules/pt/pt_peg_export.html">pt::peg::export</a></td> <td class="#doctools_tocright">PEG Export</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_export_container'><a href="files/modules/pt/pt_peg_export_container.html">pt::peg::export::container</a></td> <td class="#doctools_tocright">PEG Export Plugin. Write CONTAINER format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_export_json'><a href="files/modules/pt/pt_peg_export_json.html">pt::peg::export::json</a></td> <td class="#doctools_tocright">PEG Export Plugin. Write JSON format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_export_peg'><a href="files/modules/pt/pt_peg_export_peg.html">pt::peg::export::peg</a></td> <td class="#doctools_tocright">PEG Export Plugin. Write PEG format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_from_container'><a href="files/modules/pt/pt_peg_from_container.html">pt::peg::from::container</a></td> <td class="#doctools_tocright">PEG Conversion. From CONTAINER format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_from_json'><a href="files/modules/pt/pt_peg_from_json.html">pt::peg::from::json</a></td> <td class="#doctools_tocright">PEG Conversion. Read JSON format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_from_peg'><a href="files/modules/pt/pt_peg_from_peg.html">pt::peg::from::peg</a></td> <td class="#doctools_tocright">PEG Conversion. Read PEG format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_import'><a href="files/modules/pt/pt_peg_import.html">pt::peg::import</a></td> <td class="#doctools_tocright">PEG Import</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_import_container'><a href="files/modules/pt/pt_peg_import_container.html">pt::peg::import::container</a></td> <td class="#doctools_tocright">PEG Import Plugin. From CONTAINER format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_import_json'><a href="files/modules/pt/pt_peg_import_json.html">pt::peg::import::json</a></td> <td class="#doctools_tocright">PEG Import Plugin. Read JSON format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_import_peg'><a href="files/modules/pt/pt_peg_import_peg.html">pt::peg::import::peg</a></td> <td class="#doctools_tocright">PEG Import Plugin. Read PEG format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_interp'><a href="files/modules/pt/pt_peg_interp.html">pt::peg::interp</a></td> <td class="#doctools_tocright">Interpreter for parsing expression grammars</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_to_container'><a href="files/modules/pt/pt_peg_to_container.html">pt::peg::to::container</a></td> <td class="#doctools_tocright">PEG Conversion. Write CONTAINER format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_to_cparam'><a href="files/modules/pt/pt_peg_to_cparam.html">pt::peg::to::cparam</a></td> <td class="#doctools_tocright">PEG Conversion. Write CPARAM format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_to_json'><a href="files/modules/pt/pt_peg_to_json.html">pt::peg::to::json</a></td> <td class="#doctools_tocright">PEG Conversion. Write JSON format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_to_param'><a href="files/modules/pt/pt_peg_to_param.html">pt::peg::to::param</a></td> <td class="#doctools_tocright">PEG Conversion. Write PARAM format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_to_peg'><a href="files/modules/pt/pt_peg_to_peg.html">pt::peg::to::peg</a></td> <td class="#doctools_tocright">PEG Conversion. Write PEG format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_to_tclparam'><a href="files/modules/pt/pt_peg_to_tclparam.html">pt::peg::to::tclparam</a></td> <td class="#doctools_tocright">PEG Conversion. Write TCLPARAM format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_language'><a href="files/modules/pt/pt_peg_language.html">pt::peg_language</a></td> <td class="#doctools_tocright">PEG Language Tutorial</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_pegrammar'><a href="files/modules/pt/pt_peg_introduction.html">pt::pegrammar</a></td> <td class="#doctools_tocright">Introduction to Parsing Expression Grammars</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_pgen'><a href="files/modules/pt/pt_pgen.html">pt::pgen</a></td> <td class="#doctools_tocright">Parser Generator</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_rde'><a href="files/modules/pt/pt_rdengine.html">pt::rde</a></td> <td class="#doctools_tocright">Parsing Runtime Support, PARAM based</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_tclparam_configuration_nx'><a href="files/modules/pt/pt_tclparam_config_nx.html">pt::tclparam::configuration::nx</a></td> <td class="#doctools_tocright">Tcl/PARAM, Canned configuration, NX</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_tclparam_configuration_snit'><a href="files/modules/pt/pt_tclparam_config_snit.html">pt::tclparam::configuration::snit</a></td> <td class="#doctools_tocright">Tcl/PARAM, Canned configuration, Snit</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_tclparam_configuration_tcloo'><a href="files/modules/pt/pt_tclparam_config_tcloo.html">pt::tclparam::configuration::tcloo</a></td> <td class="#doctools_tocright">Tcl/PARAM, Canned configuration, Tcloo</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_util'><a href="files/modules/pt/pt_util.html">pt::util</a></td> <td class="#doctools_tocright">General utilities</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_export_api'><a href="files/modules/pt/pt_to_api.html">pt_export_api</a></td> <td class="#doctools_tocright">Parser Tools Export API</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_import_api'><a href="files/modules/pt/pt_from_api.html">pt_import_api</a></td> <td class="#doctools_tocright">Parser Tools Import API</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_introduction'><a href="files/modules/pt/pt_introduction.html">pt_introduction</a></td> <td class="#doctools_tocright">Introduction to Parser Tools</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_parse_peg'><a href="files/modules/pt/pt_parse_peg.html">pt_parse_peg</a></td> <td class="#doctools_tocright">Parser Tools PEG Parser</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_parser_api'><a href="files/modules/pt/pt_parser_api.html">pt_parser_api</a></td> <td class="#doctools_tocright">Parser API</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_op'><a href="files/modules/pt/pt_peg_op.html">pt_peg_op</a></td> <td class="#doctools_tocright">Parser Tools PE Grammar Utility Operations</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='rc4'><a href="files/modules/rc4/rc4.html">rc4</a></td> <td class="#doctools_tocright">Implementation of the RC4 stream cipher</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='rcs'><a href="files/modules/rcs/rcs.html">rcs</a></td> <td class="#doctools_tocright">RCS low level utilities</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='report'><a href="files/modules/report/report.html">report</a></td> <td class="#doctools_tocright">Create and manipulate report objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='rest'><a href="files/modules/rest/rest.html">rest</a></td> <td class="#doctools_tocright">define REST web APIs and call them inline or asychronously</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='ripemd128'><a href="files/modules/ripemd/ripemd128.html">ripemd128</a></td> <td class="#doctools_tocright">RIPEMD-128 Message-Digest Algorithm</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='ripemd160'><a href="files/modules/ripemd/ripemd160.html">ripemd160</a></td> <td class="#doctools_tocright">RIPEMD-160 Message-Digest Algorithm</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='s3'><a href="files/modules/amazon-s3/S3.html">S3</a></td> <td class="#doctools_tocright">Amazon S3 Web Service Interface</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='sasl'><a href="files/modules/sasl/sasl.html">SASL</a></td> <td class="#doctools_tocright">Implementation of SASL mechanisms for Tcl</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='sasl_ntlm'><a href="files/modules/sasl/ntlm.html">SASL::NTLM</a></td> <td class="#doctools_tocright">Implementation of SASL NTLM mechanism for Tcl</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='sasl_scram'><a href="files/modules/sasl/scram.html">SASL::SCRAM</a></td> <td class="#doctools_tocright">Implementation of SASL SCRAM mechanism for Tcl</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='sasl_xgoogletoken'><a href="files/modules/sasl/gtoken.html">SASL::XGoogleToken</a></td> <td class="#doctools_tocright">Implementation of SASL NTLM mechanism for Tcl</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='sha1'><a href="files/modules/sha1/sha1.html">sha1</a></td> <td class="#doctools_tocright">SHA1 Message-Digest Algorithm</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='sha256'><a href="files/modules/sha1/sha256.html">sha256</a></td> <td class="#doctools_tocright">SHA256 Message-Digest Algorithm</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_montecarlo'><a href="files/modules/simulation/montecarlo.html">simulation::montecarlo</a></td> <td class="#doctools_tocright">Monte Carlo simulations</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_random'><a href="files/modules/simulation/simulation_random.html">simulation::random</a></td> <td class="#doctools_tocright">Pseudo-random number generators</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='smtp'><a href="files/modules/mime/smtp.html">smtp</a></td> <td class="#doctools_tocright">Client-side tcl implementation of the smtp protocol</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='smtpd'><a href="files/modules/smtpd/smtpd.html">smtpd</a></td> <td class="#doctools_tocright">Tcl SMTP server implementation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='snit'><a href="files/modules/snit/snit.html">snit</a></td> <td class="#doctools_tocright">Snit's Not Incr Tcl</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='snitfaq'><a href="files/modules/snit/snitfaq.html">snitfaq</a></td> <td class="#doctools_tocright">Snit Frequently Asked Questions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='soundex'><a href="files/modules/soundex/soundex.html">soundex</a></td> <td class="#doctools_tocright">Soundex</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='stooop'><a href="files/modules/stooop/stooop.html">stooop</a></td> <td class="#doctools_tocright">Object oriented extension.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='string_token'><a href="files/modules/string/token.html">string::token</a></td> <td class="#doctools_tocright">Regex based iterative lexing</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='string_token_shell'><a href="files/modules/string/token_shell.html">string::token::shell</a></td> <td class="#doctools_tocright">Parsing of shell command line</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='stringprep'><a href="files/modules/stringprep/stringprep.html">stringprep</a></td> <td class="#doctools_tocright">Implementation of stringprep</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='stringprep_data'><a href="files/modules/stringprep/stringprep_data.html">stringprep::data</a></td> <td class="#doctools_tocright">stringprep data tables, generated, internal</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_disjointset'><a href="files/modules/struct/disjointset.html">struct::disjointset</a></td> <td class="#doctools_tocright">Disjoint set data structure</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_graph'><a href="files/modules/struct/graph.html">struct::graph</a></td> <td class="#doctools_tocright">Create and manipulate directed graph objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_graph_op'><a href="files/modules/struct/graphops.html">struct::graph::op</a></td> <td class="#doctools_tocright">Operation for (un)directed graph objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_graph_v1'><a href="files/modules/struct/graph1.html">struct::graph_v1</a></td> <td class="#doctools_tocright">Create and manipulate directed graph objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_list'><a href="files/modules/struct/struct_list.html">struct::list</a></td> <td class="#doctools_tocright">Procedures for manipulating lists</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_matrix'><a href="files/modules/struct/matrix.html">struct::matrix</a></td> <td class="#doctools_tocright">Create and manipulate matrix objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_matrix_v1'><a href="files/modules/struct/matrix1.html">struct::matrix_v1</a></td> <td class="#doctools_tocright">Create and manipulate matrix objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_pool'><a href="files/modules/struct/pool.html">struct::pool</a></td> <td class="#doctools_tocright">Create and manipulate pool objects (of discrete items)</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_prioqueue'><a href="files/modules/struct/prioqueue.html">struct::prioqueue</a></td> <td class="#doctools_tocright">Create and manipulate prioqueue objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_queue'><a href="files/modules/struct/queue.html">struct::queue</a></td> <td class="#doctools_tocright">Create and manipulate queue objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_record'><a href="files/modules/struct/record.html">struct::record</a></td> <td class="#doctools_tocright">Define and create records (similar to 'C' structures)</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_set'><a href="files/modules/struct/struct_set.html">struct::set</a></td> <td class="#doctools_tocright">Procedures for manipulating sets</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_skiplist'><a href="files/modules/struct/skiplist.html">struct::skiplist</a></td> <td class="#doctools_tocright">Create and manipulate skiplists</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_stack'><a href="files/modules/struct/stack.html">struct::stack</a></td> <td class="#doctools_tocright">Create and manipulate stack objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_tree'><a href="files/modules/struct/struct_tree.html">struct::tree</a></td> <td class="#doctools_tocright">Create and manipulate tree objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_tree_v1'><a href="files/modules/struct/struct_tree1.html">struct::tree_v1</a></td> <td class="#doctools_tocright">Create and manipulate tree objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='sum'><a href="files/modules/crc/sum.html">sum</a></td> <td class="#doctools_tocright">Calculate a sum(1) compatible checksum</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='switched'><a href="files/modules/stooop/switched.html">switched</a></td> <td class="#doctools_tocright">switch/option management.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tar'><a href="files/modules/tar/tar.html">tar</a></td> <td class="#doctools_tocright">Tar file creation, extraction & manipulation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_cat'><a href="files/modules/virtchannel_base/cat.html">tcl::chan::cat</a></td> <td class="#doctools_tocright">Concatenation channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_core'><a href="files/modules/virtchannel_core/core.html">tcl::chan::core</a></td> <td class="#doctools_tocright">Basic reflected/virtual channel support</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_events'><a href="files/modules/virtchannel_core/events.html">tcl::chan::events</a></td> <td class="#doctools_tocright">Event support for reflected/virtual channels</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_facade'><a href="files/modules/virtchannel_base/facade.html">tcl::chan::facade</a></td> <td class="#doctools_tocright">Facade channel</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_fifo'><a href="files/modules/virtchannel_base/tcllib_fifo.html">tcl::chan::fifo</a></td> <td class="#doctools_tocright">In-memory fifo channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_fifo2'><a href="files/modules/virtchannel_base/tcllib_fifo2.html">tcl::chan::fifo2</a></td> <td class="#doctools_tocright">In-memory interconnected fifo channels</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_halfpipe'><a href="files/modules/virtchannel_base/halfpipe.html">tcl::chan::halfpipe</a></td> <td class="#doctools_tocright">In-memory channel, half of a fifo2</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_memchan'><a href="files/modules/virtchannel_base/tcllib_memchan.html">tcl::chan::memchan</a></td> <td class="#doctools_tocright">In-memory channel</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_null'><a href="files/modules/virtchannel_base/tcllib_null.html">tcl::chan::null</a></td> <td class="#doctools_tocright">Null channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_nullzero'><a href="files/modules/virtchannel_base/nullzero.html">tcl::chan::nullzero</a></td> <td class="#doctools_tocright">Null/Zero channel combination</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_random'><a href="files/modules/virtchannel_base/tcllib_random.html">tcl::chan::random</a></td> <td class="#doctools_tocright">Random channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_std'><a href="files/modules/virtchannel_base/std.html">tcl::chan::std</a></td> <td class="#doctools_tocright">Standard I/O, unification of stdin and stdout</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_string'><a href="files/modules/virtchannel_base/tcllib_string.html">tcl::chan::string</a></td> <td class="#doctools_tocright">Read-only in-memory channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_textwindow'><a href="files/modules/virtchannel_base/textwindow.html">tcl::chan::textwindow</a></td> <td class="#doctools_tocright">Textwindow channel</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_variable'><a href="files/modules/virtchannel_base/tcllib_variable.html">tcl::chan::variable</a></td> <td class="#doctools_tocright">In-memory channel using variable for storage</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_zero'><a href="files/modules/virtchannel_base/tcllib_zero.html">tcl::chan::zero</a></td> <td class="#doctools_tocright">Zero channel</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_randomseed'><a href="files/modules/virtchannel_base/randseed.html">tcl::randomseed</a></td> <td class="#doctools_tocright">Utilities for random channels</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_adler32'><a href="files/modules/virtchannel_transform/adler32.html">tcl::transform::adler32</a></td> <td class="#doctools_tocright">Adler32 transformation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_base64'><a href="files/modules/virtchannel_transform/vt_base64.html">tcl::transform::base64</a></td> <td class="#doctools_tocright">Base64 encoding transformation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_core'><a href="files/modules/virtchannel_core/transformcore.html">tcl::transform::core</a></td> <td class="#doctools_tocright">Basic reflected/virtual channel transform support</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_counter'><a href="files/modules/virtchannel_transform/vt_counter.html">tcl::transform::counter</a></td> <td class="#doctools_tocright">Counter transformation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_crc32'><a href="files/modules/virtchannel_transform/vt_crc32.html">tcl::transform::crc32</a></td> <td class="#doctools_tocright">Crc32 transformation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_hex'><a href="files/modules/virtchannel_transform/hex.html">tcl::transform::hex</a></td> <td class="#doctools_tocright">Hexadecimal encoding transformation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_identity'><a href="files/modules/virtchannel_transform/identity.html">tcl::transform::identity</a></td> <td class="#doctools_tocright">Identity transformation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_limitsize'><a href="files/modules/virtchannel_transform/limitsize.html">tcl::transform::limitsize</a></td> <td class="#doctools_tocright">limiting input</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_observe'><a href="files/modules/virtchannel_transform/observe.html">tcl::transform::observe</a></td> <td class="#doctools_tocright">Observer transformation, stream copy</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_otp'><a href="files/modules/virtchannel_transform/vt_otp.html">tcl::transform::otp</a></td> <td class="#doctools_tocright">Encryption via one-time pad</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_rot'><a href="files/modules/virtchannel_transform/rot.html">tcl::transform::rot</a></td> <td class="#doctools_tocright">rot-encryption</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_spacer'><a href="files/modules/virtchannel_transform/spacer.html">tcl::transform::spacer</a></td> <td class="#doctools_tocright">Space insertation and removal</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_zlib'><a href="files/modules/virtchannel_transform/tcllib_zlib.html">tcl::transform::zlib</a></td> <td class="#doctools_tocright">zlib (de)compression</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcldes'><a href="files/modules/des/tcldes.html">tclDES</a></td> <td class="#doctools_tocright">Implementation of the DES and triple-DES ciphers</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcldesjr'><a href="files/modules/des/tcldesjr.html">tclDESjr</a></td> <td class="#doctools_tocright">Implementation of the DES and triple-DES ciphers</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcldocstrip'><a href="files/apps/tcldocstrip.html">tcldocstrip</a></td> <td class="#doctools_tocright">Tcl-based Docstrip Processor</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcllib_ip'><a href="files/modules/dns/tcllib_ip.html">tcllib_ip</a></td> <td class="#doctools_tocright">IPv4 and IPv6 address manipulation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tepam'><a href="files/modules/tepam/tepam_introduction.html">tepam</a></td> <td class="#doctools_tocright">An introduction into TEPAM, Tcl's Enhanced Procedure and Argument Manager</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tepam_argument_dialogbox'><a href="files/modules/tepam/tepam_argument_dialogbox.html">tepam::argument_dialogbox</a></td> <td class="#doctools_tocright">TEPAM argument_dialogbox, reference manual</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tepam_doc_gen'><a href="files/modules/tepam/tepam_doc_gen.html">tepam::doc_gen</a></td> <td class="#doctools_tocright">TEPAM DOC Generation, reference manual</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tepam_procedure'><a href="files/modules/tepam/tepam_procedure.html">tepam::procedure</a></td> <td class="#doctools_tocright">TEPAM procedure, reference manual</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term'><a href="files/modules/term/term.html">term</a></td> <td class="#doctools_tocright">General terminal control</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_ansi_code'><a href="files/modules/term/ansi_code.html">term::ansi::code</a></td> <td class="#doctools_tocright">Helper for control sequences</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_ansi_code_attr'><a href="files/modules/term/ansi_cattr.html">term::ansi::code::attr</a></td> <td class="#doctools_tocright">ANSI attribute sequences</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_ansi_code_ctrl'><a href="files/modules/term/ansi_cctrl.html">term::ansi::code::ctrl</a></td> <td class="#doctools_tocright">ANSI control sequences</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_ansi_code_macros'><a href="files/modules/term/ansi_cmacros.html">term::ansi::code::macros</a></td> <td class="#doctools_tocright">Macro sequences</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_ansi_ctrl_unix'><a href="files/modules/term/ansi_ctrlu.html">term::ansi::ctrl::unix</a></td> <td class="#doctools_tocright">Control operations and queries</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_ansi_send'><a href="files/modules/term/ansi_send.html">term::ansi::send</a></td> <td class="#doctools_tocright">Output of ANSI control sequences to terminals</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_interact_menu'><a href="files/modules/term/imenu.html">term::interact::menu</a></td> <td class="#doctools_tocright">Terminal widget, menu</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_interact_pager'><a href="files/modules/term/ipager.html">term::interact::pager</a></td> <td class="#doctools_tocright">Terminal widget, paging</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_receive'><a href="files/modules/term/receive.html">term::receive</a></td> <td class="#doctools_tocright">General input from terminals</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_receive_bind'><a href="files/modules/term/term_bind.html">term::receive::bind</a></td> <td class="#doctools_tocright">Keyboard dispatch from terminals</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_send'><a href="files/modules/term/term_send.html">term::send</a></td> <td class="#doctools_tocright">General output to terminals</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='textutil'><a href="files/modules/textutil/textutil.html">textutil</a></td> <td class="#doctools_tocright">Procedures to manipulate texts and strings.</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='textutil_adjust'><a href="files/modules/textutil/adjust.html">textutil::adjust</a></td> <td class="#doctools_tocright">Procedures to adjust, indent, and undent paragraphs</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='textutil_expander'><a href="files/modules/textutil/expander.html">textutil::expander</a></td> <td class="#doctools_tocright">Procedures to process templates and expand text.</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='textutil_repeat'><a href="files/modules/textutil/repeat.html">textutil::repeat</a></td> <td class="#doctools_tocright">Procedures to repeat strings.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='textutil_split'><a href="files/modules/textutil/textutil_split.html">textutil::split</a></td> <td class="#doctools_tocright">Procedures to split texts</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='textutil_string'><a href="files/modules/textutil/textutil_string.html">textutil::string</a></td> <td class="#doctools_tocright">Procedures to manipulate texts and strings.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='textutil_tabify'><a href="files/modules/textutil/tabify.html">textutil::tabify</a></td> <td class="#doctools_tocright">Procedures to (un)tabify strings</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='textutil_trim'><a href="files/modules/textutil/trim.html">textutil::trim</a></td> <td class="#doctools_tocright">Procedures to trim strings</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='throw'><a href="files/modules/try/tcllib_throw.html">throw</a></td> <td class="#doctools_tocright">throw - Throw an error exception with a message</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tie'><a href="files/modules/tie/tie_std.html">tie</a></td> <td class="#doctools_tocright">Array persistence, standard data sources</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tie'><a href="files/modules/tie/tie.html">tie</a></td> <td class="#doctools_tocright">Array persistence</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tiff'><a href="files/modules/tiff/tiff.html">tiff</a></td> <td class="#doctools_tocright">TIFF reading, writing, and querying and manipulation of meta data</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tool'><a href="files/modules/httpd/httpd.html">tool</a></td> <td class="#doctools_tocright">A TclOO and coroutine based web server</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tool'><a href="files/modules/tool/tool.html">tool</a></td> <td class="#doctools_tocright">TclOO Library (TOOL) Framework</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tool_dict_ensemble'><a href="files/modules/tool/tool_dict_ensemble.html">tool::dict_ensemble</a></td> <td class="#doctools_tocright">Dictionary Tools</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='transfer_connect'><a href="files/modules/transfer/connect.html">transfer::connect</a></td> <td class="#doctools_tocright">Connection setup</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='transfer_copy'><a href="files/modules/transfer/copyops.html">transfer::copy</a></td> <td class="#doctools_tocright">Data transfer foundation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='transfer_copy_queue'><a href="files/modules/transfer/tqueue.html">transfer::copy::queue</a></td> <td class="#doctools_tocright">Queued transfers</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='transfer_data_destination'><a href="files/modules/transfer/ddest.html">transfer::data::destination</a></td> <td class="#doctools_tocright">Data destination</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='transfer_data_source'><a href="files/modules/transfer/dsource.html">transfer::data::source</a></td> <td class="#doctools_tocright">Data source</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='transfer_receiver'><a href="files/modules/transfer/receiver.html">transfer::receiver</a></td> <td class="#doctools_tocright">Data source</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='transfer_transmitter'><a href="files/modules/transfer/transmitter.html">transfer::transmitter</a></td> <td class="#doctools_tocright">Data source</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='treeql'><a href="files/modules/treeql/treeql.html">treeql</a></td> <td class="#doctools_tocright">Query tree objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='try'><a href="files/modules/try/tcllib_try.html">try</a></td> <td class="#doctools_tocright">try - Trap and process errors and exceptions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='udpcluster'><a href="files/modules/udpcluster/udpcluster.html">udpcluster</a></td> <td class="#doctools_tocright">UDP Peer-to-Peer cluster</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='uevent'><a href="files/modules/uev/uevent.html">uevent</a></td> <td class="#doctools_tocright">User events</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='uevent_onidle'><a href="files/modules/uev/uevent_onidle.html">uevent::onidle</a></td> <td class="#doctools_tocright">Request merging and deferal to idle time</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='unicode'><a href="files/modules/stringprep/unicode.html">unicode</a></td> <td class="#doctools_tocright">Implementation of Unicode normalization</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='unicode_data'><a href="files/modules/stringprep/unicode_data.html">unicode::data</a></td> <td class="#doctools_tocright">unicode data tables, generated, internal</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='units'><a href="files/modules/units/units.html">units</a></td> <td class="#doctools_tocright">unit conversion</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='uri'><a href="files/modules/uri/uri.html">uri</a></td> <td class="#doctools_tocright">URI utilities</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='uri_urn'><a href="files/modules/uri/urn-scheme.html">uri_urn</a></td> <td class="#doctools_tocright">URI utilities, URN scheme</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='uuencode'><a href="files/modules/base64/uuencode.html">uuencode</a></td> <td class="#doctools_tocright">UU-encode/decode binary data</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='uuid'><a href="files/modules/uuid/uuid.html">uuid</a></td> <td class="#doctools_tocright">UUID generation and comparison</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_common'><a href="files/modules/valtype/valtype_common.html">valtype::common</a></td> <td class="#doctools_tocright">Validation, common code</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_creditcard_amex'><a href="files/modules/valtype/cc_amex.html">valtype::creditcard::amex</a></td> <td class="#doctools_tocright">Validation for AMEX creditcard number</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_creditcard_discover'><a href="files/modules/valtype/cc_discover.html">valtype::creditcard::discover</a></td> <td class="#doctools_tocright">Validation for Discover creditcard number</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_creditcard_mastercard'><a href="files/modules/valtype/cc_mastercard.html">valtype::creditcard::mastercard</a></td> <td class="#doctools_tocright">Validation for Mastercard creditcard number</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_creditcard_visa'><a href="files/modules/valtype/cc_visa.html">valtype::creditcard::visa</a></td> <td class="#doctools_tocright">Validation for VISA creditcard number</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_gs1_ean13'><a href="files/modules/valtype/ean13.html">valtype::gs1::ean13</a></td> <td class="#doctools_tocright">Validation for EAN13</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_iban'><a href="files/modules/valtype/iban.html">valtype::iban</a></td> <td class="#doctools_tocright">Validation for IBAN</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_imei'><a href="files/modules/valtype/imei.html">valtype::imei</a></td> <td class="#doctools_tocright">Validation for IMEI</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_isbn'><a href="files/modules/valtype/isbn.html">valtype::isbn</a></td> <td class="#doctools_tocright">Validation for ISBN</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_luhn'><a href="files/modules/valtype/luhn.html">valtype::luhn</a></td> <td class="#doctools_tocright">Validation for plain number with a LUHN checkdigit</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_luhn5'><a href="files/modules/valtype/luhn5.html">valtype::luhn5</a></td> <td class="#doctools_tocright">Validation for plain number with a LUHN5 checkdigit</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_usnpi'><a href="files/modules/valtype/usnpi.html">valtype::usnpi</a></td> <td class="#doctools_tocright">Validation for USNPI</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_verhoeff'><a href="files/modules/valtype/verhoeff.html">valtype::verhoeff</a></td> <td class="#doctools_tocright">Validation for plain number with a VERHOEFF checkdigit</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='websocket'><a href="files/modules/websocket/websocket.html">websocket</a></td> <td class="#doctools_tocright">Tcl implementation of the websocket protocol</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='wip'><a href="files/modules/wip/wip.html">wip</a></td> <td class="#doctools_tocright">Word Interpreter</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='xsxp'><a href="files/modules/amazon-s3/xsxp.html">xsxp</a></td> <td class="#doctools_tocright">eXtremely Simple Xml Parser</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='yaml'><a href="files/modules/yaml/yaml.html">yaml</a></td> <td class="#doctools_tocright">YAML Format Encoder/Decoder</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='yencode'><a href="files/modules/base64/yencode.html">yencode</a></td> <td class="#doctools_tocright">Y-encode/decode binary data</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='zipfile_decode'><a href="files/modules/zip/decode.html">zipfile::decode</a></td> <td class="#doctools_tocright">Access to zip archives</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='zipfile_encode'><a href="files/modules/zip/encode.html">zipfile::encode</a></td> <td class="#doctools_tocright">Generation of zip archives</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='zipfile_mkzip'><a href="files/modules/zip/mkzip.html">zipfile::mkzip</a></td> <td class="#doctools_tocright">Build a zip archive</td> </tr> </table> </dl><hr> |
Changes to embedded/www/toc.html.
︙ | ︙ | |||
893 894 895 896 897 898 899 900 901 902 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="tcllib/files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> | > > > > | | | 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 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="tcllib/files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="tcllib/files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_montecarlo'><a href="tcllib/files/modules/simulation/montecarlo.html">simulation::montecarlo</a></td> <td class="#doctools_tocright">Monte Carlo simulations</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_random'><a href="tcllib/files/modules/simulation/simulation_random.html">simulation::random</a></td> <td class="#doctools_tocright">Pseudo-random number generators</td> </tr> </table></dl> <dl><dt><a name='networking'>Networking<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > |
︙ | ︙ | |||
2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="tcllib/files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> </table></dl> <dl><dt><a name='md4'>md4<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > | > > > > | 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="tcllib/files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="tcllib/files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> </table></dl> <dl><dt><a name='md4'>md4<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > |
︙ | ︙ |
Changes to embedded/www/toc0.html.
︙ | ︙ | |||
893 894 895 896 897 898 899 900 901 902 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="tcllib/files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> | > > > > | | | 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 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="tcllib/files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="tcllib/files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_montecarlo'><a href="tcllib/files/modules/simulation/montecarlo.html">simulation::montecarlo</a></td> <td class="#doctools_tocright">Monte Carlo simulations</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_random'><a href="tcllib/files/modules/simulation/simulation_random.html">simulation::random</a></td> <td class="#doctools_tocright">Pseudo-random number generators</td> </tr> </table></dl> <dl><dt><a name='networking'>Networking<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > |
︙ | ︙ |
Changes to embedded/www/toc1.html.
︙ | ︙ | |||
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="tcllib/files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> </table></dl> <dl><dt><a name='md4'>md4<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > | > > > > | 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="tcllib/files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="tcllib/files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> </table></dl> <dl><dt><a name='md4'>md4<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > |
︙ | ︙ |
Added examples/httpd/htdocs/html_static_page.html.
> > > > > | 1 2 3 4 5 | <html><header><title>Static Content</title></header> <body> <h1>Static Content</h1> This page is static content embedded in the file system. Nothing fancy. </body></html> |
Changes to examples/httpd/htdocs/index.md.
1 2 3 4 5 6 7 8 9 10 11 12 13 | Your test server works! * [Tcllib embedded docs](/tcllib/index.html) * [Tcllib's fossil repo (hosted via SCGI)](/fossil) * [Standard Markdown Example Page](example.md) * [Static HTML Page](html_static_page.html) A locally served image: ![Locally Served Image](/tcllib/image/arch_core_container.png "Core Container") Internal documentation for httpd: * [Operating Principals](operations.md) | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Your test server works! * [Tcllib embedded docs](/tcllib/index.html) * [Tcllib's fossil repo (hosted via SCGI)](/fossil) * [Standard Markdown Example Page](example.md) * [Static HTML Page](html_static_page.html) * [Template HTML Page](header.tml) A locally served image: ![Locally Served Image](/tcllib/image/arch_core_container.png "Core Container") Internal documentation for httpd: * [Operating Principals](operations.md) |
︙ | ︙ |
Changes to examples/httpd/httpd.tcl.
︙ | ︙ | |||
23 24 25 26 27 28 29 | } if {[llength $args]==0} { return $::fossil_exe } return [exec ${::fossil_exe} {*}$args] } | < < < < < < < < < < < < < < < < < < | | | | | | | | | | 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 | } if {[llength $args]==0} { return $::fossil_exe } return [exec ${::fossil_exe} {*}$args] } clay::define httpd::content.fossil_node_proxy { superclass httpd::content.proxy method FileName {} { set uri [my request get REQUEST_URI] set prefix [my clay get prefix] set module [lindex [split $uri /] 2] if {![info exists ::fossil_process($module)]} { set dbfiles [::fossil-list] foreach file [lsort -dictionary $dbfiles] { dict set result [file rootname [file tail $file]] $file } if {![dict exists $result $module]} { return {} } set dbfile [dict get $result $module] if {![file exists $dbfile]} { return {} } set ::fossil_process($module) $dbfile } return [list $module $::fossil_process($module)] } method proxy_path {} { set uri [string trimleft [my request get REQUEST_URI] /] set prefix [my clay get prefix] set module [lindex [split $uri /] 1] set path /[string range $uri [string length $prefix/$module] end] return $path } method proxy_channel {} { ### # This method returns a channel to the # proxied socket/stdout/etc ### lassign [my FileName] module dbfile set EXE [my Cgi_Executable fossil] set baseurl http://[my request get HTTP_HOST][my clay get prefix]/$module if { $::tcl_platform(platform) eq "windows"} { return [open "|fossil.exe http $dbfile -baseurl $baseurl" r+] } else { return [open "|fossil http $dbfile -baseurl $baseurl 2>@1" r+] } } } clay::define httpd::content.fossil_node_scgi { superclass httpd::content.scgi method scgi_info {} { set uri [my request get REQUEST_URI] set prefix [my clay get prefix] set module [lindex [split $uri /] 2] file mkdir ~/tmp if {![info exists ::fossil_process($module)]} { package require processman package require nettool set port [::nettool::allocate_port 40000] set handle fossil:$port |
︙ | ︙ | |||
129 130 131 132 133 134 135 | my varname paused after 500 } return [list localhost $port $SCRIPT_NAME] } } | | | | < < < < < | < < < < < < < < < < < < < | | < < < < < < < < < | < < < | < < < < < < < < < < < < < < < | < | | < < < < | < < < < | | | > > > > > > > > > > > > | | < > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > | | | 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 | my varname paused after 500 } return [list localhost $port $SCRIPT_NAME] } } ::clay::define ::docserver::server { superclass ::httpd::server method debug args { #puts [list DEBUG {*}$args] } method log args { #puts [list LOG {*}$args] } } set serveropts [::httpd::server clay get server/] foreach {f v} [::clay::args_to_options {*}$::argv] { if {[dict exists $serveropts $f]} { dict set serveropts $f $v } } if {[dict exists $serveropts fossil]} { set ::fossil_exe [dict get $serveropts fossil] } ::docserver::server create appmain doc_root $DEMOROOT {*}$argv appmain plugin basic_url ::httpd::plugin.dict_dispatch appmain uri add * /tcllib* [list mixin {reply httpd::content.file} path [file join $tcllibroot embedded www]] appmain uri direct * /fossil {} { my puts "<HTML><HEAD><TITLE>Local Fossil Repositories</TITLE></HEAD><BODY>" global recipe my puts "<UL>" set dbfiles [::fossil-list] foreach file [lsort -dictionary $dbfiles] { dict set result [file rootname [file tail $file]] $file } foreach {module dbfile} [lsort -dictionary -stride 2 $result] { my puts "<li><a HREF=/fossil/$module>$module</a>" } my puts {</UL></BODY></HTML>} } appmain uri add * /fossil/* [list mixin {reply httpd::content.fossil_node_proxy}] appmain uri direct * /upload {} { my puts "<HTML><HEAD><TITLE>IRM Dispatch Server</TITLE></HEAD><BODY>" my puts "<TABLE width=100%>" set FORMDAT [my FormData] foreach {f v} [my FormData] { my puts "<tr><th>$f</th><td>$v</td></tr>" } my puts "<tr><td colspan=10><hr></td></tr>" foreach {f v} [my clay dump] { my puts "<tr><th>$f</th><td>$v</td></tr>" } my puts "<tr><td colspan=10><hr></td></tr>" foreach part [dict getnull $FORMDAT MIME_PARTS] { my puts "<tr><td colspan=10><hr></td></tr>" foreach f [::mime::getheader $part -names] { my puts "<tr><th>$f</th><td>[mime::getheader $part $f]</td></tr>" } my puts "<tr><td colspan=10>[::mime::getbody $part -decode]</td></tr>" } my puts "<tr><th>File Size</th><td>[my request get CONTENT_LENGTH]</td></tr>" my puts </TABLE> my puts </BODY></HTML> } appmain uri direct * /dynamic {} { my puts "<HTML><HEAD><TITLE>IRM Dispatch Server</TITLE></HEAD><BODY>" my puts "<TABLE width=100%>" foreach {f v} [my request dump] { my puts "<tr><th>$f</th><td>$v</td></tr>" } my puts "<tr><td colspan=10><hr></td></tr>" foreach {f v} [my clay dump] { my puts "<tr><th>$f</th><td>$v</td></tr>" } my puts "<tr><th>File Size</th><td>[my request get CONTENT_LENGTH]</td></tr>" my puts </TABLE> my puts </BODY></HTML> } puts [list LISTENING on [appmain port_listening]] cron::main |
Changes to idoc/man/files/modules/cron/cron.n.
︙ | ︙ | |||
296 297 298 299 300 301 302 | .sp \fB::cron::task info\fR \fIprocess\fR .sp \fB::cron::task set\fR \fIprocess\fR \fIfield\fR \fIvalue\fR \fI?field\&.\&.\&.?\fR \fI?value\&.\&.\&.?\fR .sp \fB::cron::wake\fR \fI?who?\fR .sp | | | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | .sp \fB::cron::task info\fR \fIprocess\fR .sp \fB::cron::task set\fR \fIprocess\fR \fIfield\fR \fIvalue\fR \fI?field\&.\&.\&.?\fR \fI?value\&.\&.\&.?\fR .sp \fB::cron::wake\fR \fI?who?\fR .sp \fB::cron::clock_step\fR \fImilliseconds\fR .sp \fB::cron::clock_delay\fR \fImilliseconds\fR .sp \fB::cron::clock_sleep\fR \fIseconds\fR \fI?offset?\fR .sp \fB::cron::clock_set\fR \fInewtime\fR .sp .BE .SH DESCRIPTION |
︙ | ︙ | |||
419 420 421 422 423 424 425 426 427 428 429 430 431 432 | \fB::cron::task info\fR \fIprocess\fR Returns a dict describing \fIprocess\fR\&. See \fB::cron::task set\fR for a description of the options\&. .TP \fB::cron::task set\fR \fIprocess\fR \fIfield\fR \fIvalue\fR \fI?field\&.\&.\&.?\fR \fI?value\&.\&.\&.?\fR .sp If \fIprocess\fR does not exist, it is created\&. Options Include: .RS \fBcommand\fR If \fBcoroutine\fR is black, a global command which implements this process\&. If \fBcoroutine\fR is not black, the command to invoke to create or recreate the coroutine\&. \fBcoroutine\fR The name of the coroutine (if any) which implements this process\&. \fBfrequency\fR If -1, this process is terminated after the next event\&. If 0 this process should be called during every | > > > | | > > | > | | | | | | 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 | \fB::cron::task info\fR \fIprocess\fR Returns a dict describing \fIprocess\fR\&. See \fB::cron::task set\fR for a description of the options\&. .TP \fB::cron::task set\fR \fIprocess\fR \fIfield\fR \fIvalue\fR \fI?field\&.\&.\&.?\fR \fI?value\&.\&.\&.?\fR .sp If \fIprocess\fR does not exist, it is created\&. Options Include: .RS .TP \fBcommand\fR If \fBcoroutine\fR is black, a global command which implements this process\&. If \fBcoroutine\fR is not black, the command to invoke to create or recreate the coroutine\&. .TP \fBcoroutine\fR The name of the coroutine (if any) which implements this process\&. .TP \fBfrequency\fR If -1, this process is terminated after the next event\&. If 0 this process should be called during every idle event\&. If positive, this process should generate events periodically\&. The frequency is an integer number of milliseconds between events\&. .TP \fBobject\fR The object associated with this process or coroutine\&. .TP \fBscheduled\fR If non-zero, the absolute time from the epoch (in milliseconds) that this process will trigger an event\&. If zero, and the \fBfrequency\fR is also zero, this process is called every idle loop\&. .TP \fBrunning\fR A boolean flag\&. If true it indicates the process never returned or yielded during the event loop, and will not be called again until it does so\&. .RE .TP \fB::cron::wake\fR \fI?who?\fR Wake up cron, and arrange for its event loop to be run during the next Idle cycle\&. .CS ::cron::wake {I just did something important} .CE .PP .PP Several utility commands are provided that are used internally within cron and for testing cron, but may or may not be useful in the general cases\&. .TP \fB::cron::clock_step\fR \fImilliseconds\fR .sp Return a clock time absolute to the epoch which falls on the next border between one second and the next for the value of \fImilliseconds\fR .TP \fB::cron::clock_delay\fR \fImilliseconds\fR .sp Return a clock time absolute to the epoch which falls on the next border between one second and the next \fImilliseconds\fR in the future\&. .TP \fB::cron::clock_sleep\fR \fIseconds\fR \fI?offset?\fR .sp Return a clock time absolute to the epoch which falls exactly \fIseconds\fR in the future\&. If offset is given it may be positive or negative, and will shift the final time to before or after the second would flip\&. .TP \fB::cron::clock_set\fR \fInewtime\fR .sp Sets the internal clock for cron\&. This command will advance the time in 100ms increment, triggering events, until the internal time catches up with \fInewtime\fR\&. .sp \fInewtime\fR is expressed in absolute milliseconds since the beginning of the epoch\&. .PP .PP .SH "BUGS, IDEAS, FEEDBACK" This document, and the package it describes, will undoubtedly contain bugs and other problems\&. Please report such in the category \fIodie\fR of the \fITcllib Trackers\fR [http://core\&.tcl\&.tk/tcllib/reportlist]\&. |
︙ | ︙ |
Changes to idoc/man/files/modules/doctools/cvs.n.
︙ | ︙ | |||
332 333 334 335 336 337 338 | order, separated by commas\&. .sp The values are lists of the files the entry is touching\&. .RE .sp .TP \fB::doctools::cvs::toChangeLog\fR \fIevar\fR \fIcvar\fR \fIfvar\fR | < | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | order, separated by commas\&. .sp The values are lists of the files the entry is touching\&. .RE .sp .TP \fB::doctools::cvs::toChangeLog\fR \fIevar\fR \fIcvar\fR \fIfvar\fR The three arguments for this command are the same as the last three arguments of the command \fB::doctools::cvs::scanLog\fR\&. This command however expects them to be filled with information about one or more logs\&. It takes this information and converts it into a text in the format of a ChangeLog as accepted and generated by \fBemacs\fR\&. The constructed text is returned as the result of the command\&. .PP |
︙ | ︙ |
Changes to idoc/man/files/modules/doctools/doctools_lang_intro.n.
︙ | ︙ | |||
372 373 374 375 376 377 378 | in the given order\&. Regular text is not allowed within the header\&. .PP Given the above a less minimal example of a document is .CS [manpage_begin NAME SECTION VERSION] | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | in the given order\&. Regular text is not allowed within the header\&. .PP Given the above a less minimal example of a document is .CS [manpage_begin NAME SECTION VERSION] [\fBcopyright {YEAR AUTHOR}\fR] [\fBtitledesc TITLE\fR] [\fBmoddesc MODULE_TITLE\fR] [\fBrequire PACKAGE VERSION\fR] [\fBrequire PACKAGE\fR] [description] [manpage_end] .CE Remember that the whitespace is optional\&. The document .CS [manpage_begin NAME SECTION VERSION] [copyright {YEAR AUTHOR}][titledesc TITLE][moddesc MODULE_TITLE] [require PACKAGE VERSION][require PACKAGE][description] [vset CATEGORY doctools] [include \&.\&./doctools2base/include/feedback\&.inc] [manpage_end] .CE has the same meaning as the example before\&. .PP On the other hand, if \fIwhitespace\fR is present it consists not only of any sequence of characters containing the space character, horizontal and vertical tabs, carriage return, and newline, but it may contain comment markup as well, in the form of the \fBcomment\fR command\&. .CS [\fBcomment { \&.\&.\&. }\fR] [manpage_begin NAME SECTION VERSION] [copyright {YEAR AUTHOR}] [titledesc TITLE] [moddesc MODULE_TITLE][\fBcomment { \&.\&.\&. }\fR] [require PACKAGE VERSION] [require PACKAGE] [description] [manpage_end] |
︙ | ︙ | |||
460 461 462 463 464 465 466 | is possible to write .CS [\fBinclude FILE\fR] [\fBvset VAR VALUE\fR] [manpage_begin NAME SECTION VERSION] | < < < < < < < < < < < < < < < < < < < < | 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 | is possible to write .CS [\fBinclude FILE\fR] [\fBvset VAR VALUE\fR] [manpage_begin NAME SECTION VERSION] [description] [manpage_end] .CE Even more important, these two commands are allowed anywhere where a markup command is allowed, without regard for any other structure\&. I\&.e\&. for example in the header as well\&. .CS [manpage_begin NAME SECTION VERSION] [\fBinclude FILE\fR] [\fBvset VAR VALUE\fR] [description] [manpage_end] .CE The only restriction \fBinclude\fR has to obey is that the contents of |
︙ | ︙ | |||
521 522 523 524 525 526 527 | the next\&. The first paragraph is automatically opened at the beginning of the body, by \fBdescription\fR\&. In the same manner the last paragraph automatically ends at \fBmanpage_end\fR\&. .CS [manpage_begin NAME SECTION VERSION] | < < < < < < < < < < | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | the next\&. The first paragraph is automatically opened at the beginning of the body, by \fBdescription\fR\&. In the same manner the last paragraph automatically ends at \fBmanpage_end\fR\&. .CS [manpage_begin NAME SECTION VERSION] [description] \&.\&.\&. [\fBpara\fR] \&.\&.\&. [\fBpara\fR] \&.\&.\&. [manpage_end] |
︙ | ︙ | |||
557 558 559 560 561 562 563 | .PP Empty sections are \fInot\fR ignored\&. We are free to (not) use paragraphs within sections\&. .CS [manpage_begin NAME SECTION VERSION] | < < < < < < < < < < | 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | .PP Empty sections are \fInot\fR ignored\&. We are free to (not) use paragraphs within sections\&. .CS [manpage_begin NAME SECTION VERSION] [description] \&.\&.\&. [\fBsection {Section A}\fR] \&.\&.\&. [para] \&.\&.\&. [\fBsection {Section B}\fR] |
︙ | ︙ | |||
592 593 594 595 596 597 598 | .PP Empty subsections are \fInot\fR ignored\&. We are free to (not) use paragraphs within subsections\&. .CS [manpage_begin NAME SECTION VERSION] | < < < < < < < < < < | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | .PP Empty subsections are \fInot\fR ignored\&. We are free to (not) use paragraphs within subsections\&. .CS [manpage_begin NAME SECTION VERSION] [description] \&.\&.\&. [section {Section A}] \&.\&.\&. [\fBsubsection {Sub 1}\fR] \&.\&.\&. [para] |
︙ | ︙ | |||
707 708 709 710 711 712 713 | highlighting added\&. It shows their use within a block of text, as the arguments of a list item command (\fBcall\fR), and our ability to nest them\&. .CS \&.\&.\&. | | | 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | highlighting added\&. It shows their use within a block of text, as the arguments of a list item command (\fBcall\fR), and our ability to nest them\&. .CS \&.\&.\&. [call [\fBcmd arg_def\fR] [\fBarg type\fR] [\fBarg name\fR] [\fBopt\fR [\fBarg mode\fR]]] Text structure\&. List element\&. Argument list\&. Automatically closes the previous list element\&. Specifies the data-[\fBarg type\fR] of the described argument of a command, its [\fBarg name\fR] and its i/o-[\fBarg mode\fR]\&. The latter is optional\&. \&.\&.\&. |
︙ | ︙ |
Changes to idoc/man/files/modules/fumagic/cfront.n.
︙ | ︙ | |||
297 298 299 300 301 302 303 | This package provides the frontend of a compiler of magic(5) files into recognizers based on the \fBfileutil::magic::rt\fR recognizer runtime package\&. For the generator backed used by this compiler see the package \fBfileutil::magic::cgen\fR\&. .SH COMMANDS .TP \fB::fileutil::magic::cfront::compile\fR \fIpath\fR\&.\&.\&. | | | | > > | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | This package provides the frontend of a compiler of magic(5) files into recognizers based on the \fBfileutil::magic::rt\fR recognizer runtime package\&. For the generator backed used by this compiler see the package \fBfileutil::magic::cgen\fR\&. .SH COMMANDS .TP \fB::fileutil::magic::cfront::compile\fR \fIpath\fR\&.\&.\&. This command takes the paths of one or more files and directories and compiles all the files, and the files in all the directories into a single analyzer for all the file types specified in these files\&. It returns a list whose first item is a list per-file dictionaries of analyzer scripts and whose second item is a list of analyzer commands\&. .sp All the files have to be in the format specified by magic(5)\&. .sp The result of the command is a Tcl script containing the generated recognizer\&. .TP \fB::fileutil::magic::cfront::procdef\fR \fIprocname\fR \fIpath\fR\&.\&.\&. |
︙ | ︙ |
Changes to idoc/man/files/modules/fumagic/rtcore.n.
︙ | ︙ | |||
277 278 279 280 281 282 283 | .sp package require \fBfileutil::magic::rt ?2\&.0?\fR .sp \fB::fileutil::magic::rt::>\fR .sp \fB::fileutil::magic::rt::<\fR .sp | < < | | < < | | | | < < < < | < < | < < | | | | | | < < < | | < > | | | < < < < < < < < < < < < < < < < < < < < < < > > > > | < < < < < < < < | | < | < < < < | | < | < < < | < > | | < | | | < < < < | < < | < < < < < < | < < < < < < < < | | < < < < < < > | > | < < < < | | 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 | .sp package require \fBfileutil::magic::rt ?2\&.0?\fR .sp \fB::fileutil::magic::rt::>\fR .sp \fB::fileutil::magic::rt::<\fR .sp \fB::fileutil::magic::rt::new\fR \fIchan\fR \fInamed\fR \fIanalyze\fR .sp \fB::fileutil::magic::rt::file_start\fR \fIname\fR .sp \fB::fileutil::magic::rt::emit\fR \fImsg\fR .sp \fB::fileutil::magic::rt::O\fR \fIwhere\fR .sp \fB::fileutil::magic::rt::R\fR \fIwhere\fR .sp \fB::fileutil::magic::rt::Nv\fR \fItype\fR \fIoffset\fR \fIcompinvert\fR \fIcomp\fR \fIexpected\fR .sp \fB::fileutil::magic::rt::N\fR \fItype\fR \fIoffset\fR \fItestinvert\fR \fIcompinvert\fR \fImod\fR \fImand\fR \fIcomp\fR \fIexpected\fR .sp \fB::fileutil::magic::rt::S\fR \fItype\fR \fIoffset\fR \fItestinvert\fR \fImod\fR \fImand\fR \fIcomp\fR \fIval\fR .sp \fB::fileutil::magic::rt::L\fR \fInewlevel\fR .sp \fB::fileutil::magic::rt::I\fR \fIoffset\fR \fIit\fR \fIioi\fR \fIioo\fR \fIiir\fR \fIio\fR .sp \fB::fileutil::magic::rt::R\fR \fIoffset\fR .sp \fB::fileutil::magic::rt::U\fR \fIfileindex\fR \fIname\fR .sp .BE .SH DESCRIPTION .PP This package provides the runtime core for file type recognition engines written in pure Tcl and is thus used by all other packages in this module such as \fBfileutil::magic::filetype\fR and the two compiler packages \fBfileutil::magic::cgen\fR and \fBfileutil::magic::cfront\fR\&. .SH COMMANDS .TP \fB::fileutil::magic::rt::>\fR Increment the level and perform related housekeeping .TP \fB::fileutil::magic::rt::<\fR Decrement the level and perform related housekeeping .TP \fB::fileutil::magic::rt::new\fR \fIchan\fR \fInamed\fR \fIanalyze\fR Create a new command which returns one description of the file each time it is called, and a code of \fIbreak\fR when there are no more descriptions\&. \fIchan\fR is the channel containing the data to describe\&. The channel configuration is then managed as needed\&. \fInamed\fR is a dictionary of named tests, as generated by \fBfileutil::magic::cfront::compile\fR\&. \fItest\fR is a command prefix for a routine composed of the list of commands as returned by \fBfileutil::magic::cfront::compile\fR\&. .TP \fB::fileutil::magic::rt::file_start\fR \fIname\fR This command marks the start of a magic file when debugging\&. It returns the empty string as its result\&. .TP \fB::fileutil::magic::rt::emit\fR \fImsg\fR This command adds the text \fImsg\fR to the result buffer\&. The message may contain the following special character sequences\&. They will be replaced with buffered values before the message is added to the result\&. The command returns the empty string as its result\&. .RS .TP \fB\\b\fR This sequence is removed .TP \fB%s\fR Replaced with the last buffered string value\&. .TP \fB%ld\fR Replaced with the last buffered numeric value\&. .TP \fB%d\fR See above\&. .TP \fB${x:\&.\&.\&.?\&.\&.\&.}\fR Substitute one string if the file is executable, and another string otherwise\&. .RE .TP \fB::fileutil::magic::rt::O\fR \fIwhere\fR Produce an offset from \fIwhere\fR, relative to the cursor one level up\&. Produce an offset from \fIwhere\fR, relative to the offset one level up\&. .TP \fB::fileutil::magic::rt::Nv\fR \fItype\fR \fIoffset\fR \fIcompinvert\fR \fIcomp\fR \fIexpected\fR A limited form of \fB::fileutile::magic::rt::N\fR that only checks for equality and can't be told to invert the test\&. .TP \fB::fileutil::magic::rt::N\fR \fItype\fR \fIoffset\fR \fItestinvert\fR \fIcompinvert\fR \fImod\fR \fImand\fR \fIcomp\fR \fIexpected\fR Fetch the numeric value with \fItype\fR from the absolute location \fIoffset\fR, compare it with \fIexpected\fR using \fIcomp\fR as the comparision operator, and returns the result\&. .sp The argument \fIcomp\fR must be one of Tcl's comparison operators\&. .CS <comp> <fetched-and-masked-value> <comp> <expected> .CE .sp The special comparison operator \fBx\fR signals that no comparison should be done, or, in other words, that the fetched value will always match \fIval\fR\&. .TP \fB::fileutil::magic::rt::S\fR \fItype\fR \fIoffset\fR \fItestinvert\fR \fImod\fR \fImand\fR \fIcomp\fR \fIval\fR Like \fB::fileutil::magic::rt::N\fR except that it fetches and compares string types , not numeric data\&. .TP \fB::fileutil::magic::rt::L\fR \fInewlevel\fR Sets the current level in the calling context to \fInewlevel\fR\&. The command returns the empty string as its result\&. .TP \fB::fileutil::magic::rt::I\fR \fIoffset\fR \fIit\fR \fIioi\fR \fIioo\fR \fIiir\fR \fIio\fR Calculates an offset based on an initial offset and the provided modifiers\&. .TP \fB::fileutil::magic::rt::R\fR \fIoffset\fR Given an initial offset, calculates an offset relative to the cursor at the next level up\&. The cursor is the position in the data one character after the data extracted from the file one level up\&. .sp .TP \fB::fileutil::magic::rt::U\fR \fIfileindex\fR \fIname\fR Add a level and use a named test script\&. .PP .SH "NUMERIC TYPES" .TP \fBbyte\fR 8-bit integer .TP \fBshort\fR |
︙ | ︙ |
Changes to idoc/man/files/modules/htmlparse/htmlparse.n.
︙ | ︙ | |||
387 388 389 390 391 392 393 | The name of the variable where to store any incomplete HTML into\&. This makes most sense for the incremental mode\&. The parser will throw an error if it sees incomplete HTML and has no place to store it to\&. This makes sense for the normal mode\&. Only incomplete tags are detected, not missing tags\&. Optional, defaults to 'no variable'\&. .RE .RS | < | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | The name of the variable where to store any incomplete HTML into\&. This makes most sense for the incremental mode\&. The parser will throw an error if it sees incomplete HTML and has no place to store it to\&. This makes sense for the normal mode\&. Only incomplete tags are detected, not missing tags\&. Optional, defaults to 'no variable'\&. .RE .RS .TP \fIInterface to the command prefix\fR In normal mode the parser will invoke the command prefix with four arguments appended\&. See \fB::htmlparse::debugCallback\fR for a description\&. .sp In incremental mode, however, the generated scripts will invoke the |
︙ | ︙ |
Changes to idoc/man/files/modules/httpd/httpd.n.
︙ | ︙ | |||
608 609 610 611 612 613 614 | tool::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 | | | 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 | tool::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 clay get doc_root] my variable reply_file set reply_file [file join $doc_root index\&.html] } } tool::define ::test::content\&.time { # return the current system time method content {} { |
︙ | ︙ | |||
641 642 643 644 645 646 647 | 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>" | | | 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 | 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>" |
︙ | ︙ |
Changes to idoc/man/files/modules/log/log.n.
︙ | ︙ | |||
429 430 431 432 433 434 435 | their priority\&. This command can be used by the -command option of lsort\&. The result is one of -1, 0 or 1 or an error\&. A result of -1 signals that level1 is of less priority than level2\&. 0 signals that both levels have the same priority\&. 1 signals that level1 has higher priority than level2\&. .TP \fB::log::lvSuppress\fR \fIlevel\fR {\fIsuppress\fR 1} | < < | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | their priority\&. This command can be used by the -command option of lsort\&. The result is one of -1, 0 or 1 or an error\&. A result of -1 signals that level1 is of less priority than level2\&. 0 signals that both levels have the same priority\&. 1 signals that level1 has higher priority than level2\&. .TP \fB::log::lvSuppress\fR \fIlevel\fR {\fIsuppress\fR 1} (Un)suppresses the output of messages having the specified level\&. Unique abbreviations for the level are allowed here too\&. .TP \fB::log::lvSuppressLE\fR \fIlevel\fR {\fIsuppress\fR 1} (Un)suppresses the output of messages having the specified level or one of lesser priority\&. Unique abbreviations for the level are allowed here too\&. .TP \fB::log::lvIsSuppressed\fR \fIlevel\fR Asks the package whether the specified level is currently suppressed\&. Unique abbreviations of level names are allowed\&. |
︙ | ︙ |
Changes to idoc/man/files/modules/math/math_geometry.n.
︙ | ︙ | |||
412 413 414 415 416 417 418 | \fIpolygon\fR - like a polyline, but the implicit assumption is that the polyline is closed (if the first and last points do not coincide, the missing segment is automatically added)\&. .IP \(bu \fIpoint set\fR - again a list of an even number of coordinates, but the points are regarded without any ordering\&. .IP \(bu | | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | \fIpolygon\fR - like a polyline, but the implicit assumption is that the polyline is closed (if the first and last points do not coincide, the missing segment is automatically added)\&. .IP \(bu \fIpoint set\fR - again a list of an even number of coordinates, but the points are regarded without any ordering\&. .IP \(bu \fIcircle\fR - a list of three numbers, the first two are the coordinates of the centre and the third is the radius\&. .PP .SH PROCEDURES The package defines the following public procedures: .TP \fB::math::geometry::+\fR \fIpoint1\fR \fIpoint2\fR Compute the sum of the two vectors given as points and return it\&. |
︙ | ︙ | |||
950 951 952 953 954 955 956 | list \fIcircle\fR Circle that may or may not be intersected .RE .TP \fB::math::geometry::intersectionCircleWithCircle\fR \fIcircle1\fR \fIcircle2\fR Determine the points at which the given two circles intersect\&. There can be zero, one or two points\&. (If the two circles touch the circle or are very close, | | | | 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 | list \fIcircle\fR Circle that may or may not be intersected .RE .TP \fB::math::geometry::intersectionCircleWithCircle\fR \fIcircle1\fR \fIcircle2\fR Determine the points at which the given two circles intersect\&. There can be zero, one or two points\&. (If the two circles touch the circle or are very close, then one point is returned\&. An arbitrary margin of 1\&.0e-10 times the mean of the radii of the two circles is used to determine this situation\&.) .RS .TP list \fIcircle1\fR First circle .TP list \fIcircle2\fR Second circle |
︙ | ︙ |
Changes to idoc/man/files/modules/math/numtheory.n.
1 2 3 4 | '\" '\" Generated from file 'numtheory\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2010 Lars Hellström <Lars dot Hellstrom at residenset dot net> '\" | | | 1 2 3 4 5 6 7 8 9 10 11 12 | '\" '\" Generated from file 'numtheory\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2010 Lars Hellström <Lars dot Hellstrom at residenset dot net> '\" .TH "math::numtheory" n 1\&.1\&.1 tcllib "Tcl Math Library" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, |
︙ | ︙ | |||
272 273 274 275 276 277 278 | .. .BS .SH NAME math::numtheory \- Number Theory .SH SYNOPSIS package require \fBTcl ?8\&.5?\fR .sp | | > > > > | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | .. .BS .SH NAME math::numtheory \- Number Theory .SH SYNOPSIS package require \fBTcl ?8\&.5?\fR .sp package require \fBmath::numtheory ?1\&.1\&.1?\fR .sp \fBmath::numtheory::isprime\fR \fIN\fR ?\fIoption\fR \fIvalue\fR \&.\&.\&.? .sp \fBmath::numtheory::firstNprimes\fR \fIN\fR .sp \fBmath::numtheory::primesLowerThan\fR \fIN\fR .sp \fBmath::numtheory::primeFactors\fR \fIN\fR .sp \fBmath::numtheory::primesLowerThan\fR \fIN\fR .sp \fBmath::numtheory::primeFactors\fR \fIN\fR .sp \fBmath::numtheory::uniquePrimeFactors\fR \fIN\fR .sp |
︙ | ︙ | |||
348 349 350 351 352 353 354 355 356 357 358 359 360 361 | \fBmath::numtheory::firstNprimes\fR \fIN\fR Return the first N primes .RS .TP integer \fIN\fR (in) Number of primes to return .RE .TP \fBmath::numtheory::primesLowerThan\fR \fIN\fR Return the prime numbers lower/equal to N .RS .TP integer \fIN\fR (in) Maximum number to consider | > > > > > > > > > > > > > > > > | 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 | \fBmath::numtheory::firstNprimes\fR \fIN\fR Return the first N primes .RS .TP integer \fIN\fR (in) Number of primes to return .RE .TP \fBmath::numtheory::primesLowerThan\fR \fIN\fR Return the prime numbers lower/equal to N .RS .TP integer \fIN\fR (in) Maximum number to consider .RE .TP \fBmath::numtheory::primeFactors\fR \fIN\fR Return a list of the prime numbers in the number N .RS .TP integer \fIN\fR (in) Number to be factorised .RE .TP \fBmath::numtheory::primesLowerThan\fR \fIN\fR Return the prime numbers lower/equal to N .RS .TP integer \fIN\fR (in) Maximum number to consider |
︙ | ︙ |
Changes to idoc/man/files/modules/math/statistics.n.
︙ | ︙ | |||
836 837 838 839 840 841 842 | - One or more groups of data to be checked .RE .sp .TP \fB::math::statistics::quantiles\fR \fIdata\fR \fIconfidence\fR Return the quantiles for a given set of data .RS | < | 836 837 838 839 840 841 842 843 844 845 846 847 848 849 | - One or more groups of data to be checked .RE .sp .TP \fB::math::statistics::quantiles\fR \fIdata\fR \fIconfidence\fR Return the quantiles for a given set of data .RS .TP list \fIdata\fR - List of raw data values .sp .TP float \fIconfidence\fR - Confidence level (0\&.95 or 0\&.99 for instance) or a list of confidence levels\&. |
︙ | ︙ |
Added idoc/man/files/modules/math/trig.n.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 | '\" '\" Generated from file 'trig\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2018 Arjen Markus '\" .TH "math::trig" n 1\&.0\&.0 tcllib "Tcl Math Library" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME math::trig \- Trigonometric anf hyperbolic functions .SH SYNOPSIS package require \fBTcl 8\&.5\fR .sp package require \fBmath::trig 1\&.0\&.0\fR .sp \fB::math::trig::radian_reduced\fR \fIangle\fR .sp \fB::math::trig::degree_reduced\fR \fIangle\fR .sp \fB::math::trig::cosec\fR \fIangle\fR .sp \fB::math::trig::sec\fR \fIangle\fR .sp \fB::math::trig::cotan\fR \fIangle\fR .sp \fB::math::trig::acosec\fR \fIvalue\fR .sp \fB::math::trig::asec\fR \fIvalue\fR .sp \fB::math::trig::acotan\fR \fIvalue\fR .sp \fB::math::trig::cosech\fR \fIvalue\fR .sp \fB::math::trig::sech\fR \fIvalue\fR .sp \fB::math::trig::cotanh\fR \fIvalue\fR .sp \fB::math::trig::asinh\fR \fIvalue\fR .sp \fB::math::trig::acosh\fR \fIvalue\fR .sp \fB::math::trig::atanh\fR \fIvalue\fR .sp \fB::math::trig::acosech\fR \fIvalue\fR .sp \fB::math::trig::asech\fR \fIvalue\fR .sp \fB::math::trig::acotanh\fR \fIvalue\fR .sp \fB::math::trig::sind\fR \fIangle\fR .sp \fB::math::trig::cosd\fR \fIangle\fR .sp \fB::math::trig::tand\fR \fIangle\fR .sp \fB::math::trig::cosecd\fR \fIangle\fR .sp \fB::math::trig::secd\fR \fIangle\fR .sp \fB::math::trig::cotand\fR \fIangle\fR .sp .BE .SH DESCRIPTION .PP The \fImath::trig\fR package defines a set of trigonomic and hyperbolic functions and their inverses\&. In addition it defines versions of the trigonomic functions that take arguments in degrees instead of radians\&. .PP For easy use these functions may be imported into the \fItcl::mathfunc\fR namespace, so that they can be used directly in the \fIexpr\fR command\&. .SH FUNCTIONS The functions \fIradian_reduced\fR and \fIdegree_reduced\fR return a reduced angle, in respectively radians and degrees, in the intervals [0, 2pi) and [0, 360): .TP \fB::math::trig::radian_reduced\fR \fIangle\fR Return the equivalent angle in the interval [0, 2pi)\&. .RS .TP float \fIangle\fR Angle (in radians) .RE .TP \fB::math::trig::degree_reduced\fR \fIangle\fR Return the equivalent angle in the interval [0, 360)\&. .RS .TP float \fIangle\fR Angle (in degrees) .RE .PP The following trigonomic functions are defined in addition to the ones defined in the \fIexpr\fR command: .TP \fB::math::trig::cosec\fR \fIangle\fR Calculate the cosecant of the angle (1/cos(angle)) .RS .TP float \fIangle\fR Angle (in radians) .RE .TP \fB::math::trig::sec\fR \fIangle\fR Calculate the secant of the angle (1/sin(angle)) .RS .TP float \fIangle\fR Angle (in radians) .RE .TP \fB::math::trig::cotan\fR \fIangle\fR Calculate the cotangent of the angle (1/tan(angle)) .RS .TP float \fIangle\fR Angle (in radians) .RE .PP For these functions also the inverses are defined: .TP \fB::math::trig::acosec\fR \fIvalue\fR Calculate the arc cosecant of the value .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::asec\fR \fIvalue\fR Calculate the arc secant of the value .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::acotan\fR \fIvalue\fR Calculate the arc cotangent of the value .RS .TP float \fIvalue\fR Value of the argument .RE .PP The following hyperbolic and inverse hyperbolic functions are defined: .TP \fB::math::trig::cosech\fR \fIvalue\fR Calculate the hyperbolic cosecant of the value (1/sinh(value)) .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::sech\fR \fIvalue\fR Calculate the hyperbolic secant of the value (1/cosh(value)) .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::cotanh\fR \fIvalue\fR Calculate the hyperbolic cotangent of the value (1/tanh(value)) .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::asinh\fR \fIvalue\fR Calculate the arc hyperbolic sine of the value .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::acosh\fR \fIvalue\fR Calculate the arc hyperbolic cosine of the value .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::atanh\fR \fIvalue\fR Calculate the arc hyperbolic tangent of the value .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::acosech\fR \fIvalue\fR Calculate the arc hyperbolic cosecant of the value .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::asech\fR \fIvalue\fR Calculate the arc hyperbolic secant of the value .RS .TP float \fIvalue\fR Value of the argument .RE .TP \fB::math::trig::acotanh\fR \fIvalue\fR Calculate the arc hyperbolic cotangent of the value .RS .TP float \fIvalue\fR Value of the argument .RE .PP The following versions of the common trigonometric functions and their inverses are defined: .TP \fB::math::trig::sind\fR \fIangle\fR Calculate the sine of the angle (in degrees) .RS .TP float \fIangle\fR Angle (in degrees) .RE .TP \fB::math::trig::cosd\fR \fIangle\fR Calculate the cosine of the angle (in degrees) .RS .TP float \fIangle\fR Angle (in radians) .RE .TP \fB::math::trig::tand\fR \fIangle\fR Calculate the cotangent of the angle (in degrees) .RS .TP float \fIangle\fR Angle (in degrees) .RE .TP \fB::math::trig::cosecd\fR \fIangle\fR Calculate the cosecant of the angle (in degrees) .RS .TP float \fIangle\fR Angle (in degrees) .RE .TP \fB::math::trig::secd\fR \fIangle\fR Calculate the secant of the angle (in degrees) .RS .TP float \fIangle\fR Angle (in degrees) .RE .TP \fB::math::trig::cotand\fR \fIangle\fR Calculate the cotangent of the angle (in degrees) .RS .TP float \fIangle\fR Angle (in degrees) .RE .PP .SH "BUGS, IDEAS, FEEDBACK" This document, and the package it describes, will undoubtedly contain bugs and other problems\&. Please report such in the category \fImath :: trig\fR of the \fITcllib Trackers\fR [http://core\&.tcl\&.tk/tcllib/reportlist]\&. Please also report any ideas for enhancements you may have for either package and/or documentation\&. .PP When proposing code changes, please provide \fIunified diffs\fR, i\&.e the output of \fBdiff -u\fR\&. .PP Note further that \fIattachments\fR are strongly preferred over inlined patches\&. Attachments can be made by going to the \fBEdit\fR form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar\&. .SH KEYWORDS math, trigonometry .SH CATEGORY Mathematics .SH COPYRIGHT .nf Copyright (c) 2018 Arjen Markus .fi |
Changes to idoc/man/files/modules/nns/nns_client.n.
︙ | ︙ | |||
402 403 404 405 406 407 408 | \fB::nameserv::configure\fR In this form the command returns a dictionary of all supported options, and their current values\&. The list of supported options and their meaning can be found in section \fBOPTIONS\fR\&. .TP \fB::nameserv::configure\fR \fB-option\fR In this form the command is an alias for | | | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | \fB::nameserv::configure\fR In this form the command returns a dictionary of all supported options, and their current values\&. The list of supported options and their meaning can be found in section \fBOPTIONS\fR\&. .TP \fB::nameserv::configure\fR \fB-option\fR In this form the command is an alias for "\fB::nameserv::cget\fR \fB-option\fR"\&. The list of supported options and their meaning can be found in section \fBOPTIONS\fR\&. .TP \fB::nameserv::configure\fR \fB-option\fR \fIvalue\fR\&.\&.\&. In this form the command is used to configure one or more of the supported options\&. At least one option has to be specified, and each option is followed by its new value\&. |
︙ | ︙ |
Changes to idoc/man/files/modules/nns/nns_server.n.
︙ | ︙ | |||
344 345 346 347 348 349 350 | \fB::nameserv::server::configure\fR In this form the command returns a dictionary of all supported options, and their current values\&. The list of supported options and their meaning can be found in section \fBOPTIONS\fR\&. .TP \fB::nameserv::server::configure\fR \fB-option\fR In this form the command is an alias for | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | \fB::nameserv::server::configure\fR In this form the command returns a dictionary of all supported options, and their current values\&. The list of supported options and their meaning can be found in section \fBOPTIONS\fR\&. .TP \fB::nameserv::server::configure\fR \fB-option\fR In this form the command is an alias for "\fB::nameserv::server::cget\fR \fB-option\fR"\&. The list of supported options and their meaning can be found in section \fBOPTIONS\fR\&. .TP \fB::nameserv::server::configure\fR \fB-option\fR \fIvalue\fR\&.\&.\&. In this form the command is used to configure one or more of the supported options\&. At least one option has to be specified, and each option is followed by its new value\&. |
︙ | ︙ |
Changes to idoc/man/files/modules/oometa/oometa.n.
︙ | ︙ | |||
420 421 422 423 424 425 426 | The package injects a new method \fBmeta\fR into \fBoo::object\fR\&. \fBoo::object\fR combines the data for its class (as provided by \fBoo::meta::metadata\fR), with a local variable \fImeta\fR to produce a local picture of metadata\&. This method provides the following additional commands: .TP \fBoo::object method meta cget\fR ?\fIfield\fR? ?\fI\&.\&.\&.\fR? \fIfield\fR Attempts to locate a singlar leaf, and return its value\&. For single option lookups, this | | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | The package injects a new method \fBmeta\fR into \fBoo::object\fR\&. \fBoo::object\fR combines the data for its class (as provided by \fBoo::meta::metadata\fR), with a local variable \fImeta\fR to produce a local picture of metadata\&. This method provides the following additional commands: .TP \fBoo::object method meta cget\fR ?\fIfield\fR? ?\fI\&.\&.\&.\fR? \fIfield\fR Attempts to locate a singlar leaf, and return its value\&. For single option lookups, this is faster than \fBmy meta getnull\fR ?\fIfield\fR? ?\fI\&.\&.\&.\fR? \fIfield\fR, because it performs a search instead directly instead of producing the recursive merge product between the class metadata, the local \fImeta\fR variable, and THEN performing the search\&. .PP .SH "BUGS, IDEAS, FEEDBACK" This document, and the package it describes, will undoubtedly contain bugs and other problems\&. Please report such in the category \fItcloo\fR of the |
︙ | ︙ |
Changes to idoc/man/files/modules/pop3d/pop3d.n.
︙ | ︙ | |||
450 451 452 453 454 455 456 | Here we describe the interface which has to be provided by the storage callback so that pop3 servers following the interface of this module are able to use it\&. The \fImbox\fR argument is the storage reference as returned by the \fBlookup\fR method of the authentication command, see section \fBAuthentication\fR\&. .TP \fIstorageCmd\fR \fBdele\fR \fImbox\fR \fImsgList\fR | < | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | Here we describe the interface which has to be provided by the storage callback so that pop3 servers following the interface of this module are able to use it\&. The \fImbox\fR argument is the storage reference as returned by the \fBlookup\fR method of the authentication command, see section \fBAuthentication\fR\&. .TP \fIstorageCmd\fR \fBdele\fR \fImbox\fR \fImsgList\fR Deletes the messages whose numeric ids are contained in the \fImsgList\fR from the mailbox specified via \fImbox\fR\&. .TP \fIstorageCmd\fR \fBlock\fR \fImbox\fR This method locks the specified mailbox for use by a single connection to the server\&. This is necessary to prevent havoc if several connections to the same mailbox are open\&. The complementary method is |
︙ | ︙ |
Changes to idoc/man/files/modules/pt/pt_peg_op.n.
1 2 3 4 | '\" '\" Generated from file 'pt_peg_op\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2009 Andreas Kupries <andreas_kupries@users\&.sourceforge\&.net> '\" | | | 1 2 3 4 5 6 7 8 9 10 11 12 | '\" '\" Generated from file 'pt_peg_op\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2009 Andreas Kupries <andreas_kupries@users\&.sourceforge\&.net> '\" .TH "pt_peg_op" i 1\&.0\&.2 tcllib "Parser Tools" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, |
︙ | ︙ | |||
272 273 274 275 276 277 278 | .. .BS .SH NAME pt_peg_op \- Parser Tools PE Grammar Utility Operations .SH SYNOPSIS package require \fBTcl 8\&.5\fR .sp | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | .. .BS .SH NAME pt_peg_op \- Parser Tools PE Grammar Utility Operations .SH SYNOPSIS package require \fBTcl 8\&.5\fR .sp package require \fBpt::peg::op ?1\&.0\&.2?\fR .sp \fB::peg::peg::op\fR \fBcalled\fR \fIcontainer\fR .sp \fB::peg::peg::op\fR \fBdechain\fR \fIcontainer\fR .sp \fB::peg::peg::op\fR \fBdrop unreachable\fR \fIcontainer\fR .sp |
︙ | ︙ |
Changes to idoc/man/files/modules/smtpd/smtpd.n.
︙ | ︙ | |||
480 481 482 483 484 485 486 | \fBvalidate_recipient\fR callback The validate_recipient callback is similar to the validate_sender callback and permits you to verify a local mailbox and accept mail for a local user address during RCPT command handling\&. To reject mail, throw an error as above\&. The error message is ignored\&. .TP \fBdeliverMIME\fR callback | < | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | \fBvalidate_recipient\fR callback The validate_recipient callback is similar to the validate_sender callback and permits you to verify a local mailbox and accept mail for a local user address during RCPT command handling\&. To reject mail, throw an error as above\&. The error message is ignored\&. .TP \fBdeliverMIME\fR callback The deliverMIME callback is called once a mail message has been successfully passed to the server\&. A mime token is constructed from the sender, recipients and data and the users procedure it called with this single argument\&. When the call returns, the mime token is cleaned up so if the user wishes to preserve the data she must make a copy\&. .sp .CS |
︙ | ︙ |
Changes to idoc/man/files/modules/stooop/switched.n.
︙ | ︙ | |||
502 503 504 505 506 507 508 | the validity of the value passed to the \fBset-\fBoption\fR\fR procedure, which should throw an error (for example by using the Tcl error command) if the value is invalid\&. .sp The switched layer also keeps track of the options current values, so that a \fBset-\fBoption\fR\fR procedure is called only when the corresponding option value passed as parameter is | | > | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | the validity of the value passed to the \fBset-\fBoption\fR\fR procedure, which should throw an error (for example by using the Tcl error command) if the value is invalid\&. .sp The switched layer also keeps track of the options current values, so that a \fBset-\fBoption\fR\fR procedure is called only when the corresponding option value passed as parameter is different from the current value (see \fB-option\fR data members description)\&. .TP \fB-option\fR .sp The \fB-option\fR data member is an options current value\&. There is one for each option listed in the options procedure\&. It is a read-only value which the switched layer checks against when an option is changed\&. It is rarely used at the layer derived from switched, except in the few cases, such as in the following example: .sp .CS |
︙ | ︙ | |||
538 539 540 541 542 543 544 545 | .CE .sp In this case, the manufacturer's name is stored at the switched layer level (this is why the set-manufacturer procedure has nothing to do) and later retrieved in the printData procedure\&. .TP .sp | > | | | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | .CE .sp In this case, the manufacturer's name is stored at the switched layer level (this is why the set-manufacturer procedure has nothing to do) and later retrieved in the printData procedure\&. .TP \fBcomplete\fR .sp The \fBcomplete\fR data member (not to be confused with the \fBcomplete\fR procedure) is a boolean\&. Its initial value is \fBfalse\fR and it is set to \fBtrue\fR at the very end of the switched \fBcomplete\fR procedure\&. It becomes useful when some options should be set at construction time only and not dynamically, as the following example shows: .sp .CS |
︙ | ︙ |
Changes to idoc/man/files/modules/tepam/tepam_doc_gen.n.
︙ | ︙ | |||
509 510 511 512 513 514 515 | The following parameters are provided to this procedure: .RS .TP \fIName\fR Name of the argument .TP \fIIsOptional\fR | | | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 | The following parameters are provided to this procedure: .RS .TP \fIName\fR Name of the argument .TP \fIIsOptional\fR If true (=\fB1\fR) the argument is optional which should be indicated by the generated string (for example by putting the argument into brackets {[]} or into question marks '?'): .CS gen(TXT,ArgumentString) mtype 1 0 string -> \fI"[mtype]"\fR .CE .TP \fIIsNamed\fR If true (=\fB1\fR) an argument is a named argument (option)\&. The generated string should in this case contain the argument/option name, followed by the argument itself: |
︙ | ︙ |
Changes to idoc/man/files/modules/tepam/tepam_procedure.n.
︙ | ︙ | |||
1120 1121 1122 1123 1124 1125 1126 | The name of the first unnamed argument has therefore not to start with the '-' character\&. The unnamed argument is otherwise considered as name of another named argument\&. This is especially important if the first unnamed argument is given by a variable that can contain any character strings: .CS my_proc \fB-n1 N1 -n2 N2 "->" "<-"\fR \fI-> my_proc: Argument '->' not known\fR set U1 "->" | | | 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 | The name of the first unnamed argument has therefore not to start with the '-' character\&. The unnamed argument is otherwise considered as name of another named argument\&. This is especially important if the first unnamed argument is given by a variable that can contain any character strings: .CS my_proc \fB-n1 N1 -n2 N2 "->" "<-"\fR \fI-> my_proc: Argument '->' not known\fR set U1 "->" my_proc \fB-n1 N1 -n2 N2 $U1 U2\fR my_proc: Argument '->' not known .CE The '--' flag allows separating unambiguously the unnamed arguments from the named arguments\&. All data after the '--' flag will be considered as unnamed argument: .CS my_proc \fB-n1 N1 -n2 N2 -- "->" "<-"\fR \fI-> n1:'N1', n2:'N2', u1:'->', u2:'<-'\fR |
︙ | ︙ |
Changes to idoc/man/files/modules/textutil/adjust.n.
︙ | ︙ | |||
372 373 374 375 376 377 378 | .RE .TP \fB-length\fR \fIinteger\fR Set the length of the \fIlogical\fR line in the string to \fIinteger\fR\&. \fIinteger\fR must be a positive integer value\&. Defaults to \fB72\fR\&. .TP | | < | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | .RE .TP \fB-length\fR \fIinteger\fR Set the length of the \fIlogical\fR line in the string to \fIinteger\fR\&. \fIinteger\fR must be a positive integer value\&. Defaults to \fB72\fR\&. .TP \fB-strictlength\fR \fIboolean\fR If set to \fBfalse\fR (default), a line can exceed the specified \fB-length\fR if a single word is longer than \fB-length\fR\&. If set to \fBtrue\fR, words that are longer than \fB-length\fR are split so that no line exceeds the specified \fB-length\fR\&. .RE .TP \fB::textutil::adjust::readPatterns\fR \fIfilename\fR |
︙ | ︙ |
Changes to idoc/man/files/modules/tool/tool_dict_ensemble.n.
︙ | ︙ | |||
272 273 274 275 276 277 278 | .. .BS .SH NAME tool::dict_ensemble \- Dictionary Tools .SH SYNOPSIS package require \fBtool ?0\&.4\&.2?\fR .sp | | | < | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | .. .BS .SH NAME tool::dict_ensemble \- Dictionary Tools .SH SYNOPSIS package require \fBtool ?0\&.4\&.2?\fR .sp \fIobject\fR \fIensemble\fR \fBadd\fR \fIfield\fR \fIvalue\fR \fIvalue \&.\&.\&.\fR .sp .BE .SH DESCRIPTION .PP The \fBdict_ensemble\fR command is a keyword added by \fBtool\fR\&. It defines a public variable (stored as a dict), and an access function to manipulated and access the values stored in that dict\&. .TP \fIobject\fR \fIensemble\fR \fBadd\fR \fIfield\fR \fIvalue\fR \fIvalue \&.\&.\&.\fR Adds elements to a list maintained with the \fIfield\fR leaf of the dict maintained my this ensemble\&. Declares a variable \fIname\fR which will be initialized as an array, populated with \fIcontents\fR for objects of this class, as well as any objects for classes which are descendents of this class\&. .PP .SH AUTHORS Sean Woods |
︙ | ︙ |
Changes to idoc/man/files/modules/websocket/websocket.n.
︙ | ︙ | |||
470 471 472 473 474 475 476 | This command registers the (accept) socket \fIsock\fR as the identifier fo an HTTP server that is capable of doing WebSockets\&. Paths onto which this server will listen for incoming connections should be declared using \fB::websocket::live\fR\&. .TP \fB::websocket::live\fR \fIsock\fR \fIpath\fR \fIcb\fR ?\fIproto\fR? This procedure registers callbacks that will be performed on a | | | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | This command registers the (accept) socket \fIsock\fR as the identifier fo an HTTP server that is capable of doing WebSockets\&. Paths onto which this server will listen for incoming connections should be declared using \fB::websocket::live\fR\&. .TP \fB::websocket::live\fR \fIsock\fR \fIpath\fR \fIcb\fR ?\fIproto\fR? This procedure registers callbacks that will be performed on a WebSocket compliant server registered with \fB::websocket::server\fR whenever a client connects to a matching path and protocol\&. \fIsock\fR is the listening socket of the websocket compliant server declared using \fB::websocket::server\fR\&. \fIpath\fR is a glob-style path to match in client request, whenever this will occur\&. \fIcb\fR is the command to callback (see Callbacks)\&. \fIproto\fR is a glob-style protocol name matcher\&. .TP |
︙ | ︙ |
Changes to idoc/man/index.n.
︙ | ︙ | |||
5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 | math::polynomials .TP \fBfiles/modules/math/rational_funcs\&.n\fR math::rationalfunctions .TP \fBfiles/modules/math/special\&.n\fR math::special .TP \fBfiles/modules/simulation/annealing\&.n\fR simulation::annealing .TP \fBfiles/modules/simulation/montecarlo\&.n\fR simulation::montecarlo .TP | > > > | 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 | math::polynomials .TP \fBfiles/modules/math/rational_funcs\&.n\fR math::rationalfunctions .TP \fBfiles/modules/math/special\&.n\fR math::special .TP \fBfiles/modules/math/trig\&.n\fR math::trig .TP \fBfiles/modules/simulation/annealing\&.n\fR simulation::annealing .TP \fBfiles/modules/simulation/montecarlo\&.n\fR simulation::montecarlo .TP |
︙ | ︙ | |||
11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 | page_util_norm_peg .RE TreeQL .RS .TP \fBfiles/modules/treeql/treeql\&.n\fR treeql .RE trimming .RS .TP \fBfiles/modules/textutil/textutil\&.n\fR textutil .TP | > > > > > > | 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 | page_util_norm_peg .RE TreeQL .RS .TP \fBfiles/modules/treeql/treeql\&.n\fR treeql .RE trigonometry .RS .TP \fBfiles/modules/math/trig\&.n\fR math::trig .RE trimming .RS .TP \fBfiles/modules/textutil/textutil\&.n\fR textutil .TP |
︙ | ︙ |
Changes to idoc/man/toc.n.
︙ | ︙ | |||
833 834 835 836 837 838 839 840 841 842 843 844 845 846 | .TP \fBmath::special\fR \fIfiles/modules/math/special\&.n\fR: Special mathematical functions .TP \fBmath::statistics\fR \fIfiles/modules/math/statistics\&.n\fR: Basic statistical functions and procedures .TP \fBmd4\fR \fIfiles/modules/md4/md4\&.n\fR: MD4 Message-Digest Algorithm .TP \fBmd5\fR \fIfiles/modules/md5/md5\&.n\fR: MD5 Message-Digest Algorithm .TP \fBmd5crypt\fR | > > > | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 | .TP \fBmath::special\fR \fIfiles/modules/math/special\&.n\fR: Special mathematical functions .TP \fBmath::statistics\fR \fIfiles/modules/math/statistics\&.n\fR: Basic statistical functions and procedures .TP \fBmath::trig\fR \fIfiles/modules/math/trig\&.n\fR: Trigonometric anf hyperbolic functions .TP \fBmd4\fR \fIfiles/modules/md4/md4\&.n\fR: MD4 Message-Digest Algorithm .TP \fBmd5\fR \fIfiles/modules/md5/md5\&.n\fR: MD5 Message-Digest Algorithm .TP \fBmd5crypt\fR |
︙ | ︙ |
Changes to idoc/www/index.html.
︙ | ︙ | |||
2261 2262 2263 2264 2265 2266 2267 | <td class="#doctools_idxleft" width="35%"><a name="matching"> matching </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/grammar_me/me_intro.html"> grammar::me_intro </a> · <a href="tcllib/files/modules/grammar_peg/peg_interp.html"> grammar::peg::interp </a> · <a href="tcllib/files/apps/pt.html"> pt </a> · <a href="tcllib/files/modules/pt/pt_astree.html"> pt::ast </a> · <a href="tcllib/files/modules/pt/pt_cparam_config_critcl.html"> pt::cparam::configuration::critcl </a> · <a href="tcllib/files/modules/pt/pt_cparam_config_tea.html"> pt::cparam::configuration::tea </a> · <a href="tcllib/files/modules/pt/pt_json_language.html"> pt::json_language </a> · <a href="tcllib/files/modules/pt/pt_param.html"> pt::param </a> · <a href="tcllib/files/modules/pt/pt_pexpression.html"> pt::pe </a> · <a href="tcllib/files/modules/pt/pt_pexpr_op.html"> pt::pe::op </a> · <a href="tcllib/files/modules/pt/pt_pegrammar.html"> pt::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_container.html"> pt::peg::container </a> · <a href="tcllib/files/modules/pt/pt_peg_container_peg.html"> pt::peg::container::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_export.html"> pt::peg::export </a> · <a href="tcllib/files/modules/pt/pt_peg_export_container.html"> pt::peg::export::container </a> · <a href="tcllib/files/modules/pt/pt_peg_export_json.html"> pt::peg::export::json </a> · <a href="tcllib/files/modules/pt/pt_peg_export_peg.html"> pt::peg::export::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_from_container.html"> pt::peg::from::container </a> · <a href="tcllib/files/modules/pt/pt_peg_from_json.html"> pt::peg::from::json </a> · <a href="tcllib/files/modules/pt/pt_peg_from_peg.html"> pt::peg::from::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_import.html"> pt::peg::import </a> · <a href="tcllib/files/modules/pt/pt_peg_import_container.html"> pt::peg::import::container </a> · <a href="tcllib/files/modules/pt/pt_peg_import_json.html"> pt::peg::import::json </a> · <a href="tcllib/files/modules/pt/pt_peg_import_peg.html"> pt::peg::import::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_interp.html"> pt::peg::interp </a> · <a href="tcllib/files/modules/pt/pt_peg_to_container.html"> pt::peg::to::container </a> · <a href="tcllib/files/modules/pt/pt_peg_to_cparam.html"> pt::peg::to::cparam </a> · <a href="tcllib/files/modules/pt/pt_peg_to_json.html"> pt::peg::to::json </a> · <a href="tcllib/files/modules/pt/pt_peg_to_param.html"> pt::peg::to::param </a> · <a href="tcllib/files/modules/pt/pt_peg_to_peg.html"> pt::peg::to::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_to_tclparam.html"> pt::peg::to::tclparam </a> · <a href="tcllib/files/modules/pt/pt_peg_language.html"> pt::peg_language </a> · <a href="tcllib/files/modules/pt/pt_peg_introduction.html"> pt::pegrammar </a> · <a href="tcllib/files/modules/pt/pt_pgen.html"> pt::pgen </a> · <a href="tcllib/files/modules/pt/pt_rdengine.html"> pt::rde </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_nx.html"> pt::tclparam::configuration::nx </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_snit.html"> pt::tclparam::configuration::snit </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_tcloo.html"> pt::tclparam::configuration::tcloo </a> · <a href="tcllib/files/modules/pt/pt_util.html"> pt::util </a> · <a href="tcllib/files/modules/pt/pt_to_api.html"> pt_export_api </a> · <a href="tcllib/files/modules/pt/pt_from_api.html"> pt_import_api </a> · <a href="tcllib/files/modules/pt/pt_introduction.html"> pt_introduction </a> · <a href="tcllib/files/modules/pt/pt_parse_peg.html"> pt_parse_peg </a> · <a href="tcllib/files/modules/pt/pt_parser_api.html"> pt_parser_api </a> · <a href="tcllib/files/modules/pt/pt_peg_op.html"> pt_peg_op </a> · <a href="tcllib/files/modules/struct/graphops.html"> struct::graph::op </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="math"> math </a></td> <td class="#doctools_idxright" width="65%"> | | | 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 | <td class="#doctools_idxleft" width="35%"><a name="matching"> matching </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/grammar_me/me_intro.html"> grammar::me_intro </a> · <a href="tcllib/files/modules/grammar_peg/peg_interp.html"> grammar::peg::interp </a> · <a href="tcllib/files/apps/pt.html"> pt </a> · <a href="tcllib/files/modules/pt/pt_astree.html"> pt::ast </a> · <a href="tcllib/files/modules/pt/pt_cparam_config_critcl.html"> pt::cparam::configuration::critcl </a> · <a href="tcllib/files/modules/pt/pt_cparam_config_tea.html"> pt::cparam::configuration::tea </a> · <a href="tcllib/files/modules/pt/pt_json_language.html"> pt::json_language </a> · <a href="tcllib/files/modules/pt/pt_param.html"> pt::param </a> · <a href="tcllib/files/modules/pt/pt_pexpression.html"> pt::pe </a> · <a href="tcllib/files/modules/pt/pt_pexpr_op.html"> pt::pe::op </a> · <a href="tcllib/files/modules/pt/pt_pegrammar.html"> pt::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_container.html"> pt::peg::container </a> · <a href="tcllib/files/modules/pt/pt_peg_container_peg.html"> pt::peg::container::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_export.html"> pt::peg::export </a> · <a href="tcllib/files/modules/pt/pt_peg_export_container.html"> pt::peg::export::container </a> · <a href="tcllib/files/modules/pt/pt_peg_export_json.html"> pt::peg::export::json </a> · <a href="tcllib/files/modules/pt/pt_peg_export_peg.html"> pt::peg::export::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_from_container.html"> pt::peg::from::container </a> · <a href="tcllib/files/modules/pt/pt_peg_from_json.html"> pt::peg::from::json </a> · <a href="tcllib/files/modules/pt/pt_peg_from_peg.html"> pt::peg::from::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_import.html"> pt::peg::import </a> · <a href="tcllib/files/modules/pt/pt_peg_import_container.html"> pt::peg::import::container </a> · <a href="tcllib/files/modules/pt/pt_peg_import_json.html"> pt::peg::import::json </a> · <a href="tcllib/files/modules/pt/pt_peg_import_peg.html"> pt::peg::import::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_interp.html"> pt::peg::interp </a> · <a href="tcllib/files/modules/pt/pt_peg_to_container.html"> pt::peg::to::container </a> · <a href="tcllib/files/modules/pt/pt_peg_to_cparam.html"> pt::peg::to::cparam </a> · <a href="tcllib/files/modules/pt/pt_peg_to_json.html"> pt::peg::to::json </a> · <a href="tcllib/files/modules/pt/pt_peg_to_param.html"> pt::peg::to::param </a> · <a href="tcllib/files/modules/pt/pt_peg_to_peg.html"> pt::peg::to::peg </a> · <a href="tcllib/files/modules/pt/pt_peg_to_tclparam.html"> pt::peg::to::tclparam </a> · <a href="tcllib/files/modules/pt/pt_peg_language.html"> pt::peg_language </a> · <a href="tcllib/files/modules/pt/pt_peg_introduction.html"> pt::pegrammar </a> · <a href="tcllib/files/modules/pt/pt_pgen.html"> pt::pgen </a> · <a href="tcllib/files/modules/pt/pt_rdengine.html"> pt::rde </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_nx.html"> pt::tclparam::configuration::nx </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_snit.html"> pt::tclparam::configuration::snit </a> · <a href="tcllib/files/modules/pt/pt_tclparam_config_tcloo.html"> pt::tclparam::configuration::tcloo </a> · <a href="tcllib/files/modules/pt/pt_util.html"> pt::util </a> · <a href="tcllib/files/modules/pt/pt_to_api.html"> pt_export_api </a> · <a href="tcllib/files/modules/pt/pt_from_api.html"> pt_import_api </a> · <a href="tcllib/files/modules/pt/pt_introduction.html"> pt_introduction </a> · <a href="tcllib/files/modules/pt/pt_parse_peg.html"> pt_parse_peg </a> · <a href="tcllib/files/modules/pt/pt_parser_api.html"> pt_parser_api </a> · <a href="tcllib/files/modules/pt/pt_peg_op.html"> pt_peg_op </a> · <a href="tcllib/files/modules/struct/graphops.html"> struct::graph::op </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="math"> math </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/math/math.html"> math </a> · <a href="tcllib/files/modules/math/bigfloat.html"> math::bigfloat </a> · <a href="tcllib/files/modules/math/bignum.html"> math::bignum </a> · <a href="tcllib/files/modules/math/calculus.html"> math::calculus </a> · <a href="tcllib/files/modules/math/qcomplex.html"> math::complexnumbers </a> · <a href="tcllib/files/modules/math/constants.html"> math::constants </a> · <a href="tcllib/files/modules/math/decimal.html"> math::decimal </a> · <a href="tcllib/files/modules/math/fuzzy.html"> math::fuzzy </a> · <a href="tcllib/files/modules/math/math_geometry.html"> math::geometry </a> · <a href="tcllib/files/modules/math/interpolate.html"> math::interpolate </a> · <a href="tcllib/files/modules/math/linalg.html"> math::linearalgebra </a> · <a href="tcllib/files/modules/math/optimize.html"> math::optimize </a> · <a href="tcllib/files/modules/math/pca.html"> math::PCA </a> · <a href="tcllib/files/modules/math/polynomials.html"> math::polynomials </a> · <a href="tcllib/files/modules/math/rational_funcs.html"> math::rationalfunctions </a> · <a href="tcllib/files/modules/math/special.html"> math::special </a> · <a href="tcllib/files/modules/math/trig.html"> math::trig </a> · <a href="tcllib/files/modules/simulation/annealing.html"> simulation::annealing </a> · <a href="tcllib/files/modules/simulation/montecarlo.html"> simulation::montecarlo </a> · <a href="tcllib/files/modules/simulation/simulation_random.html"> simulation::random </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="mathematics"> mathematics </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/math/fourier.html"> math::fourier </a> · <a href="tcllib/files/modules/math/statistics.html"> math::statistics </a> </td></tr> <tr class="#doctools_idxeven" valign=top> |
︙ | ︙ | |||
4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 | </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="treeql"> TreeQL </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/treeql/treeql.html"> treeql </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="trimming"> trimming </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/textutil/textutil.html"> textutil </a> · <a href="tcllib/files/modules/textutil/trim.html"> textutil::trim </a> </td></tr> | > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 | </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="treeql"> TreeQL </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/treeql/treeql.html"> treeql </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="trigonometry"> trigonometry </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/math/trig.html"> math::trig </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="trimming"> trimming </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/textutil/textutil.html"> textutil </a> · <a href="tcllib/files/modules/textutil/trim.html"> textutil::trim </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="twitter"> twitter </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/oauth/oauth.html"> oauth </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="type"> type </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/fileutil/fileutil.html"> fileutil </a> · <a href="tcllib/files/modules/fumagic/cfront.html"> fileutil::magic::cfront </a> · <a href="tcllib/files/modules/fumagic/cgen.html"> fileutil::magic::cgen </a> · <a href="tcllib/files/modules/fumagic/filetypes.html"> fileutil::magic::filetype </a> · <a href="tcllib/files/modules/fumagic/rtcore.html"> fileutil::magic::rt </a> · <a href="tcllib/files/modules/snit/snit.html"> snit </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="type_checking"> Type checking </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/valtype_common.html"> valtype::common </a> · <a href="tcllib/files/modules/valtype/cc_amex.html"> valtype::creditcard::amex </a> · <a href="tcllib/files/modules/valtype/cc_discover.html"> valtype::creditcard::discover </a> · <a href="tcllib/files/modules/valtype/cc_mastercard.html"> valtype::creditcard::mastercard </a> · <a href="tcllib/files/modules/valtype/cc_visa.html"> valtype::creditcard::visa </a> · <a href="tcllib/files/modules/valtype/ean13.html"> valtype::gs1::ean13 </a> · <a href="tcllib/files/modules/valtype/iban.html"> valtype::iban </a> · <a href="tcllib/files/modules/valtype/imei.html"> valtype::imei </a> · <a href="tcllib/files/modules/valtype/isbn.html"> valtype::isbn </a> · <a href="tcllib/files/modules/valtype/luhn.html"> valtype::luhn </a> · <a href="tcllib/files/modules/valtype/luhn5.html"> valtype::luhn5 </a> · <a href="tcllib/files/modules/valtype/usnpi.html"> valtype::usnpi </a> · <a href="tcllib/files/modules/valtype/verhoeff.html"> valtype::verhoeff </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cU">Keywords: U</a> </th></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uevent"> uevent </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/hook/hook.html"> hook </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="unbind"> unbind </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uev/uevent.html"> uevent </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uncapitalize"> uncapitalize </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/textutil/textutil_string.html"> textutil::string </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="undenting"> undenting </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/textutil/adjust.html"> textutil::adjust </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="unicode"> unicode </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/stringprep/stringprep.html"> stringprep </a> · <a href="tcllib/files/modules/stringprep/stringprep_data.html"> stringprep::data </a> · <a href="tcllib/files/modules/stringprep/unicode.html"> unicode </a> · <a href="tcllib/files/modules/stringprep/unicode_data.html"> unicode::data </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="union"> union </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/struct/disjointset.html"> struct::disjointset </a> · <a href="tcllib/files/modules/struct/struct_set.html"> struct::set </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="unit"> unit </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/units/units.html"> units </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="unknown_hooking"> unknown hooking </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/namespacex/namespacex.html"> namespacex </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="untie"> untie </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/tie/tie_std.html"> tie </a> · <a href="tcllib/files/modules/tie/tie.html"> tie </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="update"> update </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/coroutine/tcllib_coroutine.html"> coroutine </a> · <a href="tcllib/files/modules/coroutine/coro_auto.html"> coroutine::auto </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uri"> uri </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uri/uri.html"> uri </a> · <a href="tcllib/files/modules/uri/urn-scheme.html"> uri_urn </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="url"> url </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/doctools2idx/idx_container.html"> doctools::idx </a> · <a href="tcllib/files/modules/doctools2idx/idx_export.html"> doctools::idx::export </a> · <a href="tcllib/files/modules/doctools2idx/idx_import.html"> doctools::idx::import </a> · <a href="tcllib/files/modules/doctools2toc/toc_export.html"> doctools::toc::export </a> · <a href="tcllib/files/modules/doctools2toc/toc_import.html"> doctools::toc::import </a> · <a href="tcllib/files/modules/map/map_geocode_nominatim.html"> map::geocode::nominatim </a> · <a href="tcllib/files/modules/map/map_slippy_fetcher.html"> map::slippy::fetcher </a> · <a href="tcllib/files/modules/uri/uri.html"> uri </a> · <a href="tcllib/files/modules/uri/urn-scheme.html"> uri_urn </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="urn"> urn </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uri/urn-scheme.html"> uri_urn </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="us_npi"> US-NPI </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/usnpi.html"> valtype::usnpi </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="utilities"> utilities </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/namespacex/namespacex.html"> namespacex </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uuencode"> uuencode </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/base64/uuencode.html"> uuencode </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="uuid"> UUID </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uuid/uuid.html"> uuid </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cV">Keywords: V</a> </th></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="validation"> Validation </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/valtype_common.html"> valtype::common </a> · <a href="tcllib/files/modules/valtype/cc_amex.html"> valtype::creditcard::amex </a> · <a href="tcllib/files/modules/valtype/cc_discover.html"> valtype::creditcard::discover </a> · <a href="tcllib/files/modules/valtype/cc_mastercard.html"> valtype::creditcard::mastercard </a> · <a href="tcllib/files/modules/valtype/cc_visa.html"> valtype::creditcard::visa </a> · <a href="tcllib/files/modules/valtype/ean13.html"> valtype::gs1::ean13 </a> · <a href="tcllib/files/modules/valtype/iban.html"> valtype::iban </a> · <a href="tcllib/files/modules/valtype/imei.html"> valtype::imei </a> · <a href="tcllib/files/modules/valtype/isbn.html"> valtype::isbn </a> · <a href="tcllib/files/modules/valtype/luhn.html"> valtype::luhn </a> · <a href="tcllib/files/modules/valtype/luhn5.html"> valtype::luhn5 </a> · <a href="tcllib/files/modules/valtype/usnpi.html"> valtype::usnpi </a> · <a href="tcllib/files/modules/valtype/verhoeff.html"> valtype::verhoeff </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="value_checking"> Value checking </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/valtype_common.html"> valtype::common </a> · <a href="tcllib/files/modules/valtype/cc_amex.html"> valtype::creditcard::amex </a> · <a href="tcllib/files/modules/valtype/cc_discover.html"> valtype::creditcard::discover </a> · <a href="tcllib/files/modules/valtype/cc_mastercard.html"> valtype::creditcard::mastercard </a> · <a href="tcllib/files/modules/valtype/cc_visa.html"> valtype::creditcard::visa </a> · <a href="tcllib/files/modules/valtype/ean13.html"> valtype::gs1::ean13 </a> · <a href="tcllib/files/modules/valtype/iban.html"> valtype::iban </a> · <a href="tcllib/files/modules/valtype/imei.html"> valtype::imei </a> · <a href="tcllib/files/modules/valtype/isbn.html"> valtype::isbn </a> · <a href="tcllib/files/modules/valtype/luhn.html"> valtype::luhn </a> · <a href="tcllib/files/modules/valtype/luhn5.html"> valtype::luhn5 </a> · <a href="tcllib/files/modules/valtype/usnpi.html"> valtype::usnpi </a> · <a href="tcllib/files/modules/valtype/verhoeff.html"> valtype::verhoeff </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="vectors"> vectors </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/math/linalg.html"> math::linearalgebra </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="verhoeff"> verhoeff </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/verhoeff.html"> valtype::verhoeff </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="vertex"> vertex </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/struct/graph.html"> struct::graph </a> · <a href="tcllib/files/modules/struct/graphops.html"> struct::graph::op </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="vertex_cover"> vertex cover </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/struct/graphops.html"> struct::graph::op </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="virtual_channel"> virtual channel </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/virtchannel_base/cat.html"> tcl::chan::cat </a> · <a href="tcllib/files/modules/virtchannel_core/core.html"> tcl::chan::core </a> · <a href="tcllib/files/modules/virtchannel_core/events.html"> tcl::chan::events </a> · <a href="tcllib/files/modules/virtchannel_base/facade.html"> tcl::chan::facade </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_fifo.html"> tcl::chan::fifo </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_fifo2.html"> tcl::chan::fifo2 </a> · <a href="tcllib/files/modules/virtchannel_base/halfpipe.html"> tcl::chan::halfpipe </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_memchan.html"> tcl::chan::memchan </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_null.html"> tcl::chan::null </a> · <a href="tcllib/files/modules/virtchannel_base/nullzero.html"> tcl::chan::nullzero </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_random.html"> tcl::chan::random </a> · <a href="tcllib/files/modules/virtchannel_base/std.html"> tcl::chan::std </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_string.html"> tcl::chan::string </a> · <a href="tcllib/files/modules/virtchannel_base/textwindow.html"> tcl::chan::textwindow </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_variable.html"> tcl::chan::variable </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_zero.html"> tcl::chan::zero </a> · <a href="tcllib/files/modules/virtchannel_base/randseed.html"> tcl::randomseed </a> · <a href="tcllib/files/modules/virtchannel_transform/adler32.html"> tcl::transform::adler32 </a> · <a href="tcllib/files/modules/virtchannel_transform/vt_base64.html"> tcl::transform::base64 </a> · <a href="tcllib/files/modules/virtchannel_core/transformcore.html"> tcl::transform::core </a> · <a href="tcllib/files/modules/virtchannel_transform/vt_counter.html"> tcl::transform::counter </a> · <a href="tcllib/files/modules/virtchannel_transform/vt_crc32.html"> tcl::transform::crc32 </a> · <a href="tcllib/files/modules/virtchannel_transform/hex.html"> tcl::transform::hex </a> · <a href="tcllib/files/modules/virtchannel_transform/identity.html"> tcl::transform::identity </a> · <a href="tcllib/files/modules/virtchannel_transform/limitsize.html"> tcl::transform::limitsize </a> · <a href="tcllib/files/modules/virtchannel_transform/observe.html"> tcl::transform::observe </a> · <a href="tcllib/files/modules/virtchannel_transform/vt_otp.html"> tcl::transform::otp </a> · <a href="tcllib/files/modules/virtchannel_transform/rot.html"> tcl::transform::rot </a> · <a href="tcllib/files/modules/virtchannel_transform/spacer.html"> tcl::transform::spacer </a> · <a href="tcllib/files/modules/virtchannel_transform/tcllib_zlib.html"> tcl::transform::zlib </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="virtual_machine"> virtual machine </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/grammar_me/me_cpu.html"> grammar::me::cpu </a> · <a href="tcllib/files/modules/grammar_me/me_cpucore.html"> grammar::me::cpu::core </a> · <a href="tcllib/files/modules/grammar_me/gasm.html"> grammar::me::cpu::gasm </a> · <a href="tcllib/files/modules/grammar_me/me_tcl.html"> grammar::me::tcl </a> · <a href="tcllib/files/modules/grammar_me/me_intro.html"> grammar::me_intro </a> · <a href="tcllib/files/modules/grammar_me/me_vm.html"> grammar::me_vm </a> · <a href="tcllib/files/modules/grammar_peg/peg_interp.html"> grammar::peg::interp </a> · <a href="tcllib/files/modules/pt/pt_param.html"> pt::param </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="visa"> VISA </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/valtype/cc_visa.html"> valtype::creditcard::visa </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="vwait"> vwait </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/coroutine/tcllib_coroutine.html"> coroutine </a> · <a href="tcllib/files/modules/coroutine/coro_auto.html"> coroutine::auto </a> · <a href="tcllib/files/modules/smtpd/smtpd.html"> smtpd </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cW">Keywords: W</a> </th></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="wais"> wais </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uri/uri.html"> uri </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="widget"> widget </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/snit/snit.html"> snit </a> · <a href="tcllib/files/modules/snit/snitfaq.html"> snitfaq </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="widget_adaptors"> widget adaptors </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/snit/snit.html"> snit </a> · <a href="tcllib/files/modules/snit/snitfaq.html"> snitfaq </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="wiki"> wiki </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/doctools/docidx.html"> doctools::idx </a> · <a href="tcllib/files/modules/doctools2idx/idx_container.html"> doctools::idx </a> · <a href="tcllib/files/modules/doctools2idx/idx_export.html"> doctools::idx::export </a> · <a href="tcllib/files/modules/doctools2idx/idx_export_wiki.html"> doctools::idx::export::wiki </a> · <a href="tcllib/files/modules/doctools2toc/toc_container.html"> doctools::toc </a> · <a href="tcllib/files/modules/doctools/doctoc.html"> doctools::toc </a> · <a href="tcllib/files/modules/doctools2toc/toc_export.html"> doctools::toc::export </a> · <a href="tcllib/files/modules/doctools2toc/toc_export_wiki.html"> doctools::toc::export::wiki </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="word"> word </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/doctools2base/tcl_parse.html"> doctools::tcl::parse </a> · <a href="tcllib/files/modules/wip/wip.html"> wip </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="www"> WWW </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/httpd/httpd.html"> tool </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="www"> www </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/uri/uri.html"> uri </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cX">Keywords: X</a> </th></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="x_208"> x.208 </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/asn/asn.html"> asn </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="x_209"> x.209 </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/asn/asn.html"> asn </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="x_500"> x.500 </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/ldap/ldap.html"> ldap </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xgoogletoken"> XGoogleToken </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/sasl/gtoken.html"> SASL::XGoogleToken </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xml"> xml </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/amazon-s3/xsxp.html"> xsxp </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xor"> xor </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/virtchannel_transform/vt_otp.html"> tcl::transform::otp </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xpath"> XPath </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/treeql/treeql.html"> treeql </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="xslt"> XSLT </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/treeql/treeql.html"> treeql </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cY">Keywords: Y</a> </th></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="yaml"> yaml </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/yaml/huddle.html"> huddle </a> · <a href="tcllib/files/modules/yaml/yaml.html"> yaml </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="ydecode"> ydecode </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/base64/yencode.html"> yencode </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="yenc"> yEnc </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/base64/yencode.html"> yencode </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="yencode"> yencode </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/base64/yencode.html"> yencode </a> </td></tr> <tr class="#doctools_idxheader"><th colspan="2"> <a name="cZ">Keywords: Z</a> </th></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="zero"> zero </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/virtchannel_base/nullzero.html"> tcl::chan::nullzero </a> · <a href="tcllib/files/modules/virtchannel_base/tcllib_zero.html"> tcl::chan::zero </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="zip"> zip </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/zip/decode.html"> zipfile::decode </a> · <a href="tcllib/files/modules/zip/encode.html"> zipfile::encode </a> · <a href="tcllib/files/modules/zip/mkzip.html"> zipfile::mkzip </a> </td></tr> <tr class="#doctools_idxodd" valign=top> <td class="#doctools_idxleft" width="35%"><a name="zlib"> zlib </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/virtchannel_transform/tcllib_zlib.html"> tcl::transform::zlib </a> </td></tr> <tr class="#doctools_idxeven" valign=top> <td class="#doctools_idxleft" width="35%"><a name="zoom"> zoom </a></td> <td class="#doctools_idxright" width="65%"> <a href="tcllib/files/modules/map/map_slippy.html"> map::slippy </a> · <a href="tcllib/files/modules/map/map_slippy_cache.html"> map::slippy::cache </a> · <a href="tcllib/files/modules/map/map_slippy_fetcher.html"> map::slippy::fetcher </a> </td></tr> </table> </body></html> |
Added idoc/www/tcllib/files/modules/clay/clay.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | <!DOCTYPE html><html><head> <title>clay - Clay Framework</title> <style type="text/css"><!-- HTML { background: #FFFFFF; color: black; } BODY { background: #FFFFFF; color: black; } DIV.doctools { margin-left: 10%; margin-right: 10%; } DIV.doctools H1,DIV.doctools H2 { margin-left: -5%; } H1, H2, H3, H4 { margin-top: 1em; font-family: sans-serif; font-size: large; color: #005A9C; background: transparent; text-align: left; } H1.doctools_title { text-align: center; } UL,OL { margin-right: 0em; margin-top: 3pt; margin-bottom: 3pt; } UL LI { list-style: disc; } OL LI { list-style: decimal; } DT { padding-top: 1ex; } UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL { font: normal 12pt/14pt sans-serif; list-style: none; } LI.doctools_section, LI.doctools_subsection { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } PRE { display: block; font-family: monospace; white-space: pre; margin: 0%; padding-top: 0.5ex; padding-bottom: 0.5ex; padding-left: 1ex; padding-right: 1ex; width: 100%; } PRE.doctools_example { color: black; background: #f5dcb3; border: 1px solid black; } UL.doctools_requirements LI, UL.doctools_syntax LI { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } DIV.doctools_synopsis { color: black; background: #80ffff; border: 1px solid black; font-family: serif; margin-top: 1em; margin-bottom: 1em; } UL.doctools_syntax { margin-top: 1em; border-top: 1px solid black; } UL.doctools_requirements { margin-bottom: 1em; border-bottom: 1px solid black; } --></style> </head> <!-- Generated from file 'clay.man' by tcllib/doctools with format 'html' --> <!-- Copyright &copy; 2018 Sean Woods &lt;[email protected]&gt; --> <!-- clay.n --> <body><div class="doctools"> <h1 class="doctools_title">clay(n) 0.3 clay "Clay Framework"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>clay - A minimalist framework for large scale OO Projects</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a> <ul> <li class="doctools_subsection"><a href="#subsection1">Structured Data</a></li> <li class="doctools_subsection"><a href="#subsection2">Clay Dialect</a></li> <li class="doctools_subsection"><a href="#subsection3">Method Delegation</a></li> </ul> </li> <li class="doctools_section"><a href="#section2">Commands</a></li> <li class="doctools_section"><a href="#section3">Classes</a> <ul> <li class="doctools_subsection"><a href="#subsection4">Class oo::class</a></li> <li class="doctools_subsection"><a href="#subsection5">Class oo::object</a></li> <li class="doctools_subsection"><a href="#subsection6">Class clay::object</a></li> <li class="doctools_subsection"><a href="#subsection7">Class clay::doctool</a></li> </ul> </li> <li class="doctools_section"><a href="#section4">AUTHORS</a></li> <li class="doctools_section"><a href="#section5">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.6</b></li> <li>package require <b class="pkgname">uuid</b></li> <li>package require <b class="pkgname">oo::dialect</b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1">proc <b class="cmd">putb</b> <span class="opt">?<i class="arg">map</i>?</span> <i class="arg">text</i></a></li> <li><a href="#2">proc <b class="cmd">clay::ancestors</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#3">proc <b class="cmd">clay::args_to_dict</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#4">proc <b class="cmd">clay::args_to_options</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#5">proc <b class="cmd">clay::dictmerge</b> <i class="arg">varname</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#6">proc <b class="cmd">clay::_dictmerge</b> <i class="arg">a</i> <i class="arg">b</i></a></li> <li><a href="#7">proc <b class="cmd">clay::dictputb</b> <i class="arg">dict</i></a></li> <li><a href="#8">proc <b class="cmd">clay::_dictputb</b> <i class="arg">leaf</i> <i class="arg">level</i> <i class="arg">varname</i> <i class="arg">dict</i></a></li> <li><a href="#9">proc <b class="cmd">clay::dynamic_arguments</b> <i class="arg">ensemble</i> <i class="arg">method</i> <i class="arg">arglist</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#10">proc <b class="cmd">clay::dynamic_wrongargs_message</b> <i class="arg">arglist</i></a></li> <li><a href="#11">proc <b class="cmd">clay::is_dict</b> <i class="arg">d</i></a></li> <li><a href="#12">proc <b class="cmd">clay::is_null</b> <i class="arg">value</i></a></li> <li><a href="#13">proc <b class="cmd">clay::leaf</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#14">proc <b class="cmd">clay::path</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#15">proc <b class="cmd">clay::script_path</b></a></li> <li><a href="#16">proc <b class="cmd">clay::NSNormalize</b> <i class="arg">qualname</i></a></li> <li><a href="#17">proc <b class="cmd">clay::uuid_generate</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#18">proc <b class="cmd">clay::dynamic_methods</b> <i class="arg">class</i></a></li> <li><a href="#19">proc <b class="cmd">clay::dynamic_methods_class</b> <i class="arg">thisclass</i></a></li> <li><a href="#20">proc <b class="cmd">clay::define::Array</b> <i class="arg">name</i> <span class="opt">?<i class="arg">values</i> <b class="const"></b>?</span></a></li> <li><a href="#21">proc <b class="cmd">clay::define::component</b> <i class="arg">name</i> <i class="arg">info</i></a></li> <li><a href="#22">proc <b class="cmd">clay::define::constructor</b> <i class="arg">arglist</i> <i class="arg">rawbody</i></a></li> <li><a href="#23">proc <b class="cmd">clay::define::class_method</b> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></li> <li><a href="#24">proc <b class="cmd">clay::define::clay</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#25">proc <b class="cmd">clay::define::destructor</b> <i class="arg">rawbody</i></a></li> <li><a href="#26">proc <b class="cmd">clay::define::Dict</b> <i class="arg">name</i> <span class="opt">?<i class="arg">values</i> <b class="const"></b>?</span></a></li> <li><a href="#27">proc <b class="cmd">clay::define::Variable</b> <i class="arg">name</i> <span class="opt">?<i class="arg">default</i> <b class="const"></b>?</span></a></li> <li><a href="#28">proc <b class="cmd">clay::object_create</b> <i class="arg">objname</i> <span class="opt">?<i class="arg">class</i> <b class="const"></b>?</span></a></li> <li><a href="#29">proc <b class="cmd">clay::object_rename</b> <i class="arg">object</i> <i class="arg">newname</i></a></li> <li><a href="#30">proc <b class="cmd">clay::object_destroy</b> <i class="arg">objname</i></a></li> <li><a href="#31">proc <b class="cmd">clay::ensemble_methodbody</b> <i class="arg">ensemble</i> <i class="arg">einfo</i></a></li> <li><a href="#32">proc <b class="cmd">clay::define::Ensemble</b> <i class="arg">rawmethod</i> <i class="arg">arglist</i> <i class="arg">body</i></a></li> <li><a href="#33">proc <b class="cmd">clay::cat</b> <i class="arg">fname</i></a></li> <li><a href="#34">proc <b class="cmd">clay::docstrip</b> <i class="arg">text</i></a></li> <li><a href="#35">method <b class="cmd">clay ancestors</b></a></li> <li><a href="#36">method <b class="cmd">clay dump</b></a></li> <li><a href="#37">method <b class="cmd">clay get</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#38">method <b class="cmd">clay merge</b> <i class="arg">dict</i> <span class="opt">?<b class="option">dict...</b>?</span></a></li> <li><a href="#39">method <b class="cmd">clay replace</b> <i class="arg">dictionary</i></a></li> <li><a href="#40">method <b class="cmd">clay search</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#41">method <b class="cmd">clay set</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span> <i class="arg">value</i></a></li> <li><a href="#42">method <b class="cmd">clay ancestors</b></a></li> <li><a href="#43">method <b class="cmd">clay cget</b> <i class="arg">field</i></a></li> <li><a href="#44">method <b class="cmd">clay delegate</b> <span class="opt">?<i class="arg">stub</i>?</span> <span class="opt">?<i class="arg">object</i>?</span></a></li> <li><a href="#45">method <b class="cmd">clay dump</b></a></li> <li><a href="#46">method <b class="cmd">clay ensemble_map</b></a></li> <li><a href="#47">method <b class="cmd">clay eval</b> <i class="arg">script</i></a></li> <li><a href="#48">method <b class="cmd">clay evolve</b></a></li> <li><a href="#49">method <b class="cmd">clay exists</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#50">method <b class="cmd">clay flush</b></a></li> <li><a href="#51">method <b class="cmd">clay forward</b> <i class="arg">method</i> <i class="arg">object</i></a></li> <li><a href="#52">method <b class="cmd">clay get</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#53">method <b class="cmd">clay leaf</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#54">method <b class="cmd">clay merge</b> <i class="arg">dict</i> <span class="opt">?<b class="option">dict...</b>?</span></a></li> <li><a href="#55">method <b class="cmd">clay mixin</b> <i class="arg">class</i> <span class="opt">?<b class="option">class...</b>?</span></a></li> <li><a href="#56">method <b class="cmd">clay mixinmap</b> <span class="opt">?<i class="arg">stub</i>?</span> <span class="opt">?<i class="arg">classes</i>?</span></a></li> <li><a href="#57">method <b class="cmd">clay provenance</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></li> <li><a href="#58">method <b class="cmd">clay replace</b> <i class="arg">dictionary</i></a></li> <li><a href="#59">method <b class="cmd">clay source</b> <i class="arg">filename</i></a></li> <li><a href="#60">method <b class="cmd">clay set</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span> <i class="arg">value</i></a></li> <li><a href="#61">method <b class="cmd">InitializePublic</b></a></li> <li><a href="#62">method <b class="cmd">InitializePublic</b></a></li> <li><a href="#63">method <b class="cmd">constructor</b></a></li> <li><a href="#64">method <b class="cmd">arglist</b> <i class="arg">arglist</i></a></li> <li><a href="#65">method <b class="cmd">comment</b> <i class="arg">block</i></a></li> <li><a href="#66">method <b class="cmd">keyword.Class</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">body</i></a></li> <li><a href="#67">method <b class="cmd">keyword.class</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">body</i></a></li> <li><a href="#68">method <b class="cmd">keyword.class_method</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#69">method <b class="cmd">keyword.method</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#70">method <b class="cmd">keyword.proc</b> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></li> <li><a href="#71">method <b class="cmd">reset</b></a></li> <li><a href="#72">method <b class="cmd">Main</b></a></li> <li><a href="#73">method <b class="cmd">section.method</b> <i class="arg">keyword</i> <i class="arg">method</i> <i class="arg">minfo</i></a></li> <li><a href="#74">method <b class="cmd">section.class</b> <i class="arg">class_name</i> <i class="arg">class_info</i></a></li> <li><a href="#75">method <b class="cmd">section.command</b> <i class="arg">procinfo</i></a></li> <li><a href="#76">method <b class="cmd">manpage</b> <span class="opt">?<b class="option">header <em>value</em></b>?</span> <span class="opt">?<b class="option">footer <em>value</em></b>?</span> <span class="opt">?<b class="option">authors <em>list</em></b>?</span></a></li> <li><a href="#77">method <b class="cmd">scan_text</b> <i class="arg">text</i></a></li> <li><a href="#78">method <b class="cmd">scan_file</b> <i class="arg">filename</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>Clay introduces a method ensemble to both <b class="class">oo::class</b> and <b class="class">oo::object</b> called clay. This ensemble handles all of the high level interactions within the framework. Clay stores structured data. Clan manages method delegation. Clay has facilities to manage the complex interactions that come about with mixins.</p> <p>The central concept is that inside of every object and class (which are actually objects too) is a dict called clay. What is stored in that dict is left to the imagination. But because this dict is exposed via a public method, we can share structured data between object, classes, and mixins.</p> <div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Structured Data</a></h3> <p>Clay uses a standardized set of method interactions and introspection that TclOO already provides to perform on-the-fly searches. On-the-fly searches mean that the data is never stale, and we avoid many of the sorts of collisions that would arise when objects start mixing in other classes during operation.</p> <p>The <b class="method">clay</b> methods for both classes and objects have a get and a set method. For objects, get will search through the local clay dict. If the requested leaf is not found, or the query is for a branch, the system will then begin to poll the clay methods of all of the class that implements the object, all of that classes’ ancestors, as well as all of the classes that have been mixed into this object, and all of their ancestors.</p> <p>Intended branches on a tree end with a directory slash (/). Intended leaves are left unadorned. This is a guide for the tool that builds the search results to know what parts of a dict are intended to be branches and which are intended to be leaves. For simple cases, branch marking can be ignored:</p> <pre class="doctools_example"> ::oo::class create ::foo { } ::foo clay set property/ color blue ::foo clay set property/ shape round set A [::foo new] $A clay get property/ {color blue shape round} $A clay set property/ shape square $A clay get property/ {color blue shape square} </pre> <p>But when you start storing blocks of text, guessing what field is a dict and what isn’t gets messy:</p> <pre class="doctools_example"> ::foo clay set description {A generic thing of designated color and shape} $A clay get description {A generic thing of designated color and shape} Without a convention for discerning branches for leaves what should have been a value can be accidentally parsed as a dictionary, and merged with all of the other values that were never intended to be merge. Here is an example of it all going wrong: ::oo::class create ::foo { } # Add description as a leaf ::foo clay set description {A generic thing of designated color and shape} # Add description as a branch ::foo clay set description/ {A generic thing of designated color and shape} ::oo::class create ::bar { superclass foo } # Add description as a leaf ::bar clay set description {A drinking establishment of designated color and shape and size} # Add description as a branch ::bar clay set description/ {A drinking establishment of designated color and shape and size} set B [::bar new] # As a leaf we get the value verbatim from he nearest ancestor $B clay get description {A drinking establishment of designated color and shape and size} # As a branch we get a recursive merge $B clay get description/ {A drinking establishment of designated color and size thing of} </pre> </div> <div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">Clay Dialect</a></h3> <p>Clay is built using the oo::dialect module from Tcllib. oo::dialect allows you to either add keywords directly to clay, or to create your own metaclass and keyword set using Clay as a foundation. For details on the keywords and what they do, consult the functions in the ::clay::define namespace.</p> </div> <div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Method Delegation</a></h3> <p>Method Delegation It is sometimes useful to have an external object that can be invoked as if it were a method of the object. Clay provides a delegate ensemble method to perform that delegation, as well as introspect which methods are delegated in that manner. All delegated methods are marked with html-like tag markings (< >) around them.</p> <pre class="doctools_example"> ::clay::define counter { Variable counter 0 method incr {{howmuch 1}} { my variable counter incr counter $howmuch } method value {} { my variable counter return $counter } method reset {} { my variable counter set counter 0 } } ::clay::define example { variable buffer constructor {} { # Build a counter object set obj [namespace current]::counter ::counter create $obj # Delegate the counter my delegate <counter> $obj } method line {text} { my <counter> incr append buffer $text } } set A [example new] $A line {Who’s line is it anyway?} $A <counter> value 1 </pre> </div> </div> <div id="section2" class="doctools_section"><h2><a name="section2">Commands</a></h2> <dl class="doctools_definitions"> <dt><a name="1">proc <b class="cmd">putb</b> <span class="opt">?<i class="arg">map</i>?</span> <i class="arg">text</i></a></dt> <dd><p>Append a line of text to a variable. Optionally apply a string mapping.</p></dd> <dt><a name="2">proc <b class="cmd">clay::ancestors</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="3">proc <b class="cmd">clay::args_to_dict</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="4">proc <b class="cmd">clay::args_to_options</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="5">proc <b class="cmd">clay::dictmerge</b> <i class="arg">varname</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="6">proc <b class="cmd">clay::_dictmerge</b> <i class="arg">a</i> <i class="arg">b</i></a></dt> <dd></dd> <dt><a name="7">proc <b class="cmd">clay::dictputb</b> <i class="arg">dict</i></a></dt> <dd></dd> <dt><a name="8">proc <b class="cmd">clay::_dictputb</b> <i class="arg">leaf</i> <i class="arg">level</i> <i class="arg">varname</i> <i class="arg">dict</i></a></dt> <dd></dd> <dt><a name="9">proc <b class="cmd">clay::dynamic_arguments</b> <i class="arg">ensemble</i> <i class="arg">method</i> <i class="arg">arglist</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="10">proc <b class="cmd">clay::dynamic_wrongargs_message</b> <i class="arg">arglist</i></a></dt> <dd></dd> <dt><a name="11">proc <b class="cmd">clay::is_dict</b> <i class="arg">d</i></a></dt> <dd></dd> <dt><a name="12">proc <b class="cmd">clay::is_null</b> <i class="arg">value</i></a></dt> <dd></dd> <dt><a name="13">proc <b class="cmd">clay::leaf</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="14">proc <b class="cmd">clay::path</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="15">proc <b class="cmd">clay::script_path</b></a></dt> <dd></dd> <dt><a name="16">proc <b class="cmd">clay::NSNormalize</b> <i class="arg">qualname</i></a></dt> <dd></dd> <dt><a name="17">proc <b class="cmd">clay::uuid_generate</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="18">proc <b class="cmd">clay::dynamic_methods</b> <i class="arg">class</i></a></dt> <dd></dd> <dt><a name="19">proc <b class="cmd">clay::dynamic_methods_class</b> <i class="arg">thisclass</i></a></dt> <dd></dd> <dt><a name="20">proc <b class="cmd">clay::define::Array</b> <i class="arg">name</i> <span class="opt">?<i class="arg">values</i> <b class="const"></b>?</span></a></dt> <dd><p>New OO Keywords for clay</p></dd> <dt><a name="21">proc <b class="cmd">clay::define::component</b> <i class="arg">name</i> <i class="arg">info</i></a></dt> <dd></dd> <dt><a name="22">proc <b class="cmd">clay::define::constructor</b> <i class="arg">arglist</i> <i class="arg">rawbody</i></a></dt> <dd></dd> <dt><a name="23">proc <b class="cmd">clay::define::class_method</b> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="24">proc <b class="cmd">clay::define::clay</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="25">proc <b class="cmd">clay::define::destructor</b> <i class="arg">rawbody</i></a></dt> <dd></dd> <dt><a name="26">proc <b class="cmd">clay::define::Dict</b> <i class="arg">name</i> <span class="opt">?<i class="arg">values</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="27">proc <b class="cmd">clay::define::Variable</b> <i class="arg">name</i> <span class="opt">?<i class="arg">default</i> <b class="const"></b>?</span></a></dt> <dd><p>This keyword can also be expressed:</p> <pre class="doctools_example">property variable NAME {default DEFAULT}</pre> <p>Variables registered in the variable property are also initialized (if missing) when the object changes class via the <em>morph</em> method.</p></dd> <dt><a name="28">proc <b class="cmd">clay::object_create</b> <i class="arg">objname</i> <span class="opt">?<i class="arg">class</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="29">proc <b class="cmd">clay::object_rename</b> <i class="arg">object</i> <i class="arg">newname</i></a></dt> <dd></dd> <dt><a name="30">proc <b class="cmd">clay::object_destroy</b> <i class="arg">objname</i></a></dt> <dd></dd> <dt><a name="31">proc <b class="cmd">clay::ensemble_methodbody</b> <i class="arg">ensemble</i> <i class="arg">einfo</i></a></dt> <dd></dd> <dt><a name="32">proc <b class="cmd">clay::define::Ensemble</b> <i class="arg">rawmethod</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="33">proc <b class="cmd">clay::cat</b> <i class="arg">fname</i></a></dt> <dd><p>Concatenate a file</p></dd> <dt><a name="34">proc <b class="cmd">clay::docstrip</b> <i class="arg">text</i></a></dt> <dd><p>Strip the global comments from tcl code. Used to prevent the documentation markup comments from clogging up files intended for distribution in machine readable format.</p></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Classes</a></h2> <div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Class oo::class</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="35">method <b class="cmd">clay ancestors</b></a></dt> <dd><p>Return this class and all ancestors in search order.</p></dd> <dt><a name="36">method <b class="cmd">clay dump</b></a></dt> <dd><p>Return a complete dump of this object's clay data, but only this object's clay data.</p></dd> <dt><a name="37">method <b class="cmd">clay get</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Pull a chunk of data from the clay system. If the last element of <em>path</em> is a branch (ends in a slash /), returns a recursive merge of all data from this object and it's constituent classes of the data in that branch. If the last element is a leaf, search this object for a matching leaf, or search all constituent classes for a matching leaf and return the first value found. If no value is found, returns an empty string.</p></dd> <dt><a name="38">method <b class="cmd">clay merge</b> <i class="arg">dict</i> <span class="opt">?<b class="option">dict...</b>?</span></a></dt> <dd><p>Recursively merge the dictionaries given into the object's local clay storage.</p></dd> <dt><a name="39">method <b class="cmd">clay replace</b> <i class="arg">dictionary</i></a></dt> <dd><p>Replace the contents of the internal clay storage with the dictionary given.</p></dd> <dt><a name="40">method <b class="cmd">clay search</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Return the first matching value for the path in either this class's clay data or one of its ancestors</p></dd> <dt><a name="41">method <b class="cmd">clay set</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span> <i class="arg">value</i></a></dt> <dd><p>Merge the conents of <b class="const">value</b> with the object's clay storage at <b class="const">path</b>.</p></dd> </dl> </div> <div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Class oo::object</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="42">method <b class="cmd">clay ancestors</b></a></dt> <dd><p>Return the class this object belongs to, all classes mixed into this object, and all ancestors of those classes in search order.</p></dd> <dt><a name="43">method <b class="cmd">clay cget</b> <i class="arg">field</i></a></dt> <dd><p>Pull a value from either the object's clay structure or one of its constituent classes that matches the field name. The order of search us:</p> <p>1. The as a value in local dict variable config</p> <p>2. The as a value in local dict variable clay</p> <p>3. As a leaf in any ancestor as a root of the clay tree</p> <p>4. As a leaf in any ancestor under the const/ branch of the clay tree</p></dd> <dt><a name="44">method <b class="cmd">clay delegate</b> <span class="opt">?<i class="arg">stub</i>?</span> <span class="opt">?<i class="arg">object</i>?</span></a></dt> <dd><p>Introspect or control method delegation. With no arguments, the method will return a key/value list of stubs and objects. With just the <i class="arg">stub</i> argument, the method will return the object (if any) attached to the stub. With a <i class="arg">stub</i> and an <i class="arg">object</i> this command will forward all calls to the method <i class="arg">stub</i> to the <i class="arg">object</i>.</p></dd> <dt><a name="45">method <b class="cmd">clay dump</b></a></dt> <dd><p>Return a complete dump of this object's clay data, as well as the data from all constituent classes recursively blended in.</p></dd> <dt><a name="46">method <b class="cmd">clay ensemble_map</b></a></dt> <dd><p>Return a dictionary describing the method ensembles to be assembled for this object</p></dd> <dt><a name="47">method <b class="cmd">clay eval</b> <i class="arg">script</i></a></dt> <dd><p>Evaluated a script in the namespace of this object</p></dd> <dt><a name="48">method <b class="cmd">clay evolve</b></a></dt> <dd><p>Trigger the <b class="method">InitializePublic</b> private method</p></dd> <dt><a name="49">method <b class="cmd">clay exists</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Returns 1 if <em>path</em> exists in either the object's clay data. Values greater than one indicate the element exists in one of the object's constituent classes. A value of zero indicates the path could not be found.</p></dd> <dt><a name="50">method <b class="cmd">clay flush</b></a></dt> <dd><p>Wipe any caches built by the clay implementation</p></dd> <dt><a name="51">method <b class="cmd">clay forward</b> <i class="arg">method</i> <i class="arg">object</i></a></dt> <dd><p>A convenience wrapper for</p> <pre class="doctools_example">oo::objdefine [self] forward {*}$args</pre> </dd> <dt><a name="52">method <b class="cmd">clay get</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Pull a chunk of data from the clay system. If the last element of <em>path</em> is a branch (ends in a slash /), returns a recursive merge of all data from this object and it's constituent classes of the data in that branch. If the last element is a leaf, search this object for a matching leaf, or search all constituent classes for a matching leaf and return the first value found. If no value is found, returns an empty string.</p></dd> <dt><a name="53">method <b class="cmd">clay leaf</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>A modified get which is tailored to pull only leaf elements</p></dd> <dt><a name="54">method <b class="cmd">clay merge</b> <i class="arg">dict</i> <span class="opt">?<b class="option">dict...</b>?</span></a></dt> <dd><p>Recursively merge the dictionaries given into the object's local clay storage.</p></dd> <dt><a name="55">method <b class="cmd">clay mixin</b> <i class="arg">class</i> <span class="opt">?<b class="option">class...</b>?</span></a></dt> <dd><p>Perform [oo::objdefine [self] mixin] on this object, with a few additional rules: Prior to the call, for any class was previously mixed in, but not in the new result, execute the script registered to mixin/ unmap-script (if given.) For all new classes, that were not present prior to this call, after the native TclOO mixin is invoked, execute the script registered to mixin/ map-script (if given.) Fall all classes that are now present and “mixed in”, execute the script registered to mixin/ react-script (if given.)</p></dd> <dt><a name="56">method <b class="cmd">clay mixinmap</b> <span class="opt">?<i class="arg">stub</i>?</span> <span class="opt">?<i class="arg">classes</i>?</span></a></dt> <dd><p>With no arguments returns the map of stubs and classes mixed into the current object. When only stub is given, returns the classes mixed in on that stub. When stub and classlist given, replace the classes currently on that stub with the given classes and invoke clay mixin on the new matrix of mixed in classes.</p></dd> <dt><a name="57">method <b class="cmd">clay provenance</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span></a></dt> <dd><p>Return either <b class="const">self</b> if that path exists in the current object, or return the first class (if any) along the clay search path which contains that element.</p></dd> <dt><a name="58">method <b class="cmd">clay replace</b> <i class="arg">dictionary</i></a></dt> <dd><p>Replace the contents of the internal clay storage with the dictionary given.</p></dd> <dt><a name="59">method <b class="cmd">clay source</b> <i class="arg">filename</i></a></dt> <dd><p>Source the given filename within the object's namespace</p></dd> <dt><a name="60">method <b class="cmd">clay set</b> <i class="arg">path</i> <span class="opt">?<b class="option">path...</b>?</span> <i class="arg">value</i></a></dt> <dd><p>Merge the conents of <b class="const">value</b> with the object's clay storage at <b class="const">path</b>.</p></dd> <dt><a name="61">method <b class="cmd">InitializePublic</b></a></dt> <dd><p>Instantiate variables. Called on object creation and during clay mixin.</p></dd> </dl> </div> <div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Class clay::object</a></h3> <p>clay::object This class is inherited by all classes that have options.</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="62">method <b class="cmd">InitializePublic</b></a></dt> <dd><p>Instantiate variables and build ensemble methods.</p></dd> </dl> </div> <div id="subsection7" class="doctools_subsection"><h3><a name="subsection7">Class clay::doctool</a></h3> <pre class="doctools_example">{ set authors { {John Doe} {[email protected]} {Tom RichardHarry} {[email protected]} } # Create the object ::clay::doctool create AutoDoc set fout [open [file join $moddir module.tcl] w] foreach file [glob [file join $srcdir *.tcl]] { set content [::clay::cat [file join $srcdir $file]] # Scan the file AutoDoc scan_text $content # Strip the comments from the distribution puts $fout [::clay::docstrip $content] } # Write out the manual page set manout [open [file join $moddir module.man] w] dict set arglist header [string map $modmap [::clay::cat [file join $srcdir manual.txt]]] dict set arglist footer [string map $modmap [::clay::cat [file join $srcdir footer.txt]]] dict set arglist authors $authors puts $manout [AutoDoc manpage {*}$arglist] close $manout }</pre> <p>Tool for build scripts to dynamically generate manual files from comments in source code files</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="63">method <b class="cmd">constructor</b></a></dt> <dd></dd> <dt><a name="64">method <b class="cmd">arglist</b> <i class="arg">arglist</i></a></dt> <dd><p>Process an argument list into an informational dict. This method also understands non-positional arguments expressed in the notation of Tip 471 <a href="https://core.tcl-lang.org/tips/doc/trunk/tip/479.md">https://core.tcl-lang.org/tips/doc/trunk/tip/479.md</a>.</p> <p>The output will be a dictionary of all of the fields and whether the fields are <b class="const">positional</b>, <b class="const">mandatory</b>, and whether they have a <b class="const">default</b> value.</p> <p>Example:</p> <pre class="doctools_example"> my arglist {a b {c 10}} > a {positional 1 mandatory 1} b {positional 1 mandatory 1} c {positional 1 mandatory 0 default 10} </pre> </dd> <dt><a name="65">method <b class="cmd">comment</b> <i class="arg">block</i></a></dt> <dd><p>Convert a block of comments into an informational dictionary. If lines in the comment start with a single word ending in a colon, all subsequent lines are appended to a dictionary field of that name. If no fields are given, all of the text is appended to the <b class="const">description</b> field.</p> <p>Example:</p> <pre class="doctools_example"> my comment {Does something cool} > description {Does something cool} my comment { title : Something really cool author : Sean Woods author : John Doe description : This does something really cool! } > description {This does something really cool!} title {Something really cool} author {Sean Woods John Doe} </pre> </dd> <dt><a name="66">method <b class="cmd">keyword.Class</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">body</i></a></dt> <dd><p>Process an oo::objdefine call that modifies the class object itself</p></dd> <dt><a name="67">method <b class="cmd">keyword.class</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">body</i></a></dt> <dd><p>Process an oo::define, clay::define, etc statement.</p></dd> <dt><a name="68">method <b class="cmd">keyword.class_method</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Process a statement for a clay style class method</p></dd> <dt><a name="69">method <b class="cmd">keyword.method</b> <i class="arg">resultvar</i> <i class="arg">commentblock</i> <i class="arg">name</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Process a statement for a tcloo style object method</p></dd> <dt><a name="70">method <b class="cmd">keyword.proc</b> <i class="arg">commentblock</i> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd><p>Process a proc statement</p></dd> <dt><a name="71">method <b class="cmd">reset</b></a></dt> <dd><p>Reset the state of the object and its embedded coroutine</p></dd> <dt><a name="72">method <b class="cmd">Main</b></a></dt> <dd><p>Main body of the embedded coroutine for the object</p></dd> <dt><a name="73">method <b class="cmd">section.method</b> <i class="arg">keyword</i> <i class="arg">method</i> <i class="arg">minfo</i></a></dt> <dd><p>Generate the manual page text for a method or proc</p></dd> <dt><a name="74">method <b class="cmd">section.class</b> <i class="arg">class_name</i> <i class="arg">class_info</i></a></dt> <dd><p>Generate the manual page text for a class</p></dd> <dt><a name="75">method <b class="cmd">section.command</b> <i class="arg">procinfo</i></a></dt> <dd><p>Generate the manual page text for the commands section</p></dd> <dt><a name="76">method <b class="cmd">manpage</b> <span class="opt">?<b class="option">header <em>value</em></b>?</span> <span class="opt">?<b class="option">footer <em>value</em></b>?</span> <span class="opt">?<b class="option">authors <em>list</em></b>?</span></a></dt> <dd><p>Generate the manual page. Returns the completed text suitable for saving in .man file. The header argument is a block of doctools text to go in before the machine generated section. footer is a block of doctools text to go in after the machine generated section. authors is a list of individual authors and emails in the form of AUTHOR EMAIL ?AUTHOR EMAIL?...</p></dd> <dt><a name="77">method <b class="cmd">scan_text</b> <i class="arg">text</i></a></dt> <dd><p>Scan a block of text</p></dd> <dt><a name="78">method <b class="cmd">scan_file</b> <i class="arg">filename</i></a></dt> <dd><p>Scan a file of text</p></dd> </dl> </div> </div> <div id="section4" class="doctools_section"><h2><a name="section4">AUTHORS</a></h2> <p>Sean Woods <a href="mailto:<[email protected]>">mailto:<[email protected]></a></p> </div> <div id="section5" class="doctools_section"><h2><a name="section5">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>oo</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. Please also report any ideas for enhancements you may have for either package and/or documentation.</p> <p>When proposing code changes, please provide <em>unified diffs</em>, i.e the output of <b class="const">diff -u</b>.</p> <p>Note further that <em>attachments</em> are strongly preferred over inlined patches. Attachments can be made by going to the <b class="const">Edit</b> form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p>TclOO, oo</p> </div> <div id="category" class="doctools_section"><h2><a name="category">Category</a></h2> <p>Programming tools</p> </div> <div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> <p>Copyright © 2018 Sean Woods <[email protected]></p> </div> </div></body></html> |
Changes to idoc/www/tcllib/files/modules/cron/cron.html.
︙ | ︙ | |||
138 139 140 141 142 143 144 | <li><a href="#5"><b class="cmd">::cron::object_coroutine</b> <i class="arg">object</i> <i class="arg">coroutine</i> <i class="arg">?info?</i></a></li> <li><a href="#6"><b class="cmd">::cron::sleep</b> <i class="arg">milliseconds</i></a></li> <li><a href="#7"><b class="cmd">::cron::task delete</b> <i class="arg">process</i></a></li> <li><a href="#8"><b class="cmd">::cron::task exists</b> <i class="arg">process</i></a></li> <li><a href="#9"><b class="cmd">::cron::task info</b> <i class="arg">process</i></a></li> <li><a href="#10"><b class="cmd">::cron::task set</b> <i class="arg">process</i> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">?field...?</i> <i class="arg">?value...?</i></a></li> <li><a href="#11"><b class="cmd">::cron::wake</b> <i class="arg">?who?</i></a></li> | | | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | <li><a href="#5"><b class="cmd">::cron::object_coroutine</b> <i class="arg">object</i> <i class="arg">coroutine</i> <i class="arg">?info?</i></a></li> <li><a href="#6"><b class="cmd">::cron::sleep</b> <i class="arg">milliseconds</i></a></li> <li><a href="#7"><b class="cmd">::cron::task delete</b> <i class="arg">process</i></a></li> <li><a href="#8"><b class="cmd">::cron::task exists</b> <i class="arg">process</i></a></li> <li><a href="#9"><b class="cmd">::cron::task info</b> <i class="arg">process</i></a></li> <li><a href="#10"><b class="cmd">::cron::task set</b> <i class="arg">process</i> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">?field...?</i> <i class="arg">?value...?</i></a></li> <li><a href="#11"><b class="cmd">::cron::wake</b> <i class="arg">?who?</i></a></li> <li><a href="#12"><b class="cmd">::cron::clock_step</b> <i class="arg">milliseconds</i></a></li> <li><a href="#13"><b class="cmd">::cron::clock_delay</b> <i class="arg">milliseconds</i></a></li> <li><a href="#14"><b class="cmd">::cron::clock_sleep</b> <i class="arg">seconds</i> <i class="arg">?offset?</i></a></li> <li><a href="#15"><b class="cmd">::cron::clock_set</b> <i class="arg">newtime</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>The <b class="package">cron</b> package provides a Pure-tcl set of tools to allow |
︙ | ︙ | |||
233 234 235 236 237 238 239 | <dt><a name="8"><b class="cmd">::cron::task exists</b> <i class="arg">process</i></a></dt> <dd><p>Returns true if <i class="arg">process</i> is registered with cron.</p></dd> <dt><a name="9"><b class="cmd">::cron::task info</b> <i class="arg">process</i></a></dt> <dd><p>Returns a dict describing <i class="arg">process</i>. See <b class="cmd">::cron::task set</b> for a description of the options.</p></dd> <dt><a name="10"><b class="cmd">::cron::task set</b> <i class="arg">process</i> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">?field...?</i> <i class="arg">?value...?</i></a></dt> <dd><p>If <i class="arg">process</i> does not exist, it is created. Options Include:</p> <dl class="doctools_definitions"> | | | | | | | | | | | | | | | | | | | | | | | | 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 | <dt><a name="8"><b class="cmd">::cron::task exists</b> <i class="arg">process</i></a></dt> <dd><p>Returns true if <i class="arg">process</i> is registered with cron.</p></dd> <dt><a name="9"><b class="cmd">::cron::task info</b> <i class="arg">process</i></a></dt> <dd><p>Returns a dict describing <i class="arg">process</i>. See <b class="cmd">::cron::task set</b> for a description of the options.</p></dd> <dt><a name="10"><b class="cmd">::cron::task set</b> <i class="arg">process</i> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">?field...?</i> <i class="arg">?value...?</i></a></dt> <dd><p>If <i class="arg">process</i> does not exist, it is created. Options Include:</p> <dl class="doctools_definitions"> <dt><b class="cmd"><a href="../../../../index.html#command">command</a></b></dt> <dd><p>If <b class="cmd"><a href="../coroutine/tcllib_coroutine.html">coroutine</a></b> is black, a global command which implements this process. If <b class="cmd"><a href="../coroutine/tcllib_coroutine.html">coroutine</a></b> is not black, the command to invoke to create or recreate the coroutine.</p></dd> <dt><b class="cmd"><a href="../coroutine/tcllib_coroutine.html">coroutine</a></b></dt> <dd><p>The name of the coroutine (if any) which implements this process.</p></dd> <dt><b class="cmd">frequency</b></dt> <dd><p>If -1, this process is terminated after the next event. If 0 this process should be called during every idle event. If positive, this process should generate events periodically. The frequency is an integer number of milliseconds between events.</p></dd> <dt><b class="cmd"><a href="../../../../index.html#object">object</a></b></dt> <dd><p>The object associated with this process or coroutine.</p></dd> <dt><b class="cmd">scheduled</b></dt> <dd><p>If non-zero, the absolute time from the epoch (in milliseconds) that this process will trigger an event. If zero, and the <b class="cmd">frequency</b> is also zero, this process is called every idle loop.</p></dd> <dt><b class="cmd"><a href="../../../../index.html#running">running</a></b></dt> <dd><p>A boolean flag. If true it indicates the process never returned or yielded during the event loop, and will not be called again until it does so.</p></dd> </dl></dd> <dt><a name="11"><b class="cmd">::cron::wake</b> <i class="arg">?who?</i></a></dt> <dd><p>Wake up cron, and arrange for its event loop to be run during the next Idle cycle.</p> <pre class="doctools_example"> ::cron::wake {I just did something important} </pre> </dd> </dl> <p>Several utility commands are provided that are used internally within cron and for testing cron, but may or may not be useful in the general cases.</p> <dl class="doctools_definitions"> <dt><a name="12"><b class="cmd">::cron::clock_step</b> <i class="arg">milliseconds</i></a></dt> <dd><p>Return a clock time absolute to the epoch which falls on the next border between one second and the next for the value of <i class="arg">milliseconds</i></p></dd> <dt><a name="13"><b class="cmd">::cron::clock_delay</b> <i class="arg">milliseconds</i></a></dt> <dd><p>Return a clock time absolute to the epoch which falls on the next border between one second and the next <i class="arg">milliseconds</i> in the future.</p></dd> <dt><a name="14"><b class="cmd">::cron::clock_sleep</b> <i class="arg">seconds</i> <i class="arg">?offset?</i></a></dt> <dd><p>Return a clock time absolute to the epoch which falls exactly <i class="arg">seconds</i> in the future. If offset is given it may be positive or negative, and will shift the final time to before or after the second would flip.</p></dd> <dt><a name="15"><b class="cmd">::cron::clock_set</b> <i class="arg">newtime</i></a></dt> <dd><p>Sets the internal clock for cron. This command will advance the time in 100ms increment, triggering events, until the internal time catches up with <i class="arg">newtime</i>.</p> <p><i class="arg">newtime</i> is expressed in absolute milliseconds since the beginning of the epoch.</p></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>odie</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/doctools/cvs.html.
︙ | ︙ | |||
175 176 177 178 179 180 181 | <dt>varname <i class="arg">fvar</i> (in)</dt> <dd><p>Has to refer to an array variable. Keys are strings containing date, author of a log entry, and a comment for that entry, in this order, separated by commas.</p> <p>The values are lists of the files the entry is touching.</p></dd> </dl></dd> <dt><a name="2"><b class="cmd">::doctools::cvs::toChangeLog</b> <i class="arg">evar</i> <i class="arg">cvar</i> <i class="arg">fvar</i></a></dt> | < | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | <dt>varname <i class="arg">fvar</i> (in)</dt> <dd><p>Has to refer to an array variable. Keys are strings containing date, author of a log entry, and a comment for that entry, in this order, separated by commas.</p> <p>The values are lists of the files the entry is touching.</p></dd> </dl></dd> <dt><a name="2"><b class="cmd">::doctools::cvs::toChangeLog</b> <i class="arg">evar</i> <i class="arg">cvar</i> <i class="arg">fvar</i></a></dt> <dd><p>The three arguments for this command are the same as the last three arguments of the command <b class="cmd">::doctools::cvs::scanLog</b>. This command however expects them to be filled with information about one or more logs. It takes this information and converts it into a text in the format of a ChangeLog as accepted and generated by <b class="syscmd"><a href="../../../../index.html#emacs">emacs</a></b>. The constructed text is returned as the result of the command.</p></dd> </dl> </div> |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/doctools/doctools_lang_intro.html.
︙ | ︙ | |||
225 226 227 228 229 230 231 | [<b class="cmd">require PACKAGE</b>] [description] [manpage_end] </pre> <p>Remember that the whitespace is optional. The document</p> <pre class="doctools_example"> [manpage_begin NAME SECTION VERSION] | < < < < < < < < < < | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | [<b class="cmd">require PACKAGE</b>] [description] [manpage_end] </pre> <p>Remember that the whitespace is optional. The document</p> <pre class="doctools_example"> [manpage_begin NAME SECTION VERSION] [copyright {YEAR AUTHOR}][titledesc TITLE][moddesc MODULE_TITLE] [require PACKAGE VERSION][require PACKAGE][description] [vset CATEGORY doctools] [include ../doctools2base/include/feedback.inc] [manpage_end] </pre> <p>has the same meaning as the example before.</p> |
︙ | ︙ | |||
429 430 431 432 433 434 435 | <p>The example demonstrating the use of text markup is an excerpt from the <i class="term"><a href="doctools_lang_cmdref.html">doctools language command reference</a></i>, with some highlighting added. It shows their use within a block of text, as the arguments of a list item command (<b class="cmd">call</b>), and our ability to nest them.</p> <pre class="doctools_example"> ... | | | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | <p>The example demonstrating the use of text markup is an excerpt from the <i class="term"><a href="doctools_lang_cmdref.html">doctools language command reference</a></i>, with some highlighting added. It shows their use within a block of text, as the arguments of a list item command (<b class="cmd">call</b>), and our ability to nest them.</p> <pre class="doctools_example"> ... [call [<b class="cmd">cmd arg_def</b>] [<b class="cmd">arg type</b>] [<b class="cmd">arg name</b>] [<b class="cmd">opt</b> [<b class="cmd">arg mode</b>]]] Text structure. List element. Argument list. Automatically closes the previous list element. Specifies the data-[<b class="cmd">arg type</b>] of the described argument of a command, its [<b class="cmd">arg name</b>] and its i/o-[<b class="cmd">arg mode</b>]. The latter is optional. ... </pre> </div> |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/fumagic/cfront.html.
︙ | ︙ | |||
144 145 146 147 148 149 150 | into recognizers based on the <b class="package"><a href="rtcore.html">fileutil::magic::rt</a></b> recognizer runtime package. For the generator backed used by this compiler see the package <b class="package"><a href="cgen.html">fileutil::magic::cgen</a></b>.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">COMMANDS</a></h2> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::fileutil::magic::cfront::compile</b> <i class="arg">path</i>...</a></dt> | | | | > > | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | into recognizers based on the <b class="package"><a href="rtcore.html">fileutil::magic::rt</a></b> recognizer runtime package. For the generator backed used by this compiler see the package <b class="package"><a href="cgen.html">fileutil::magic::cgen</a></b>.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">COMMANDS</a></h2> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::fileutil::magic::cfront::compile</b> <i class="arg">path</i>...</a></dt> <dd><p>This command takes the paths of one or more files and directories and compiles all the files, and the files in all the directories into a single analyzer for all the file types specified in these files. It returns a list whose first item is a list per-file dictionaries of analyzer scripts and whose second item is a list of analyzer commands.</p> <p>All the files have to be in the format specified by magic(5).</p> <p>The result of the command is a Tcl script containing the generated recognizer.</p></dd> <dt><a name="2"><b class="cmd">::fileutil::magic::cfront::procdef</b> <i class="arg">procname</i> <i class="arg">path</i>...</a></dt> <dd><p>This command behaves like <b class="cmd">::fileutil::magic::cfront::compile</b> with regard to the specified path arguments, then wraps the resulting recognizer script into a procedure named <i class="arg">procname</i>, puts code |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/fumagic/rtcore.html.
︙ | ︙ | |||
128 129 130 131 132 133 134 | <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.5</b></li> <li>package require <b class="pkgname">fileutil::magic::rt <span class="opt">?2.0?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">::fileutil::magic::rt::></b></a></li> <li><a href="#2"><b class="cmd">::fileutil::magic::rt::<</b></a></li> | | | | | | | | < | < < < < | | | | < | < | | | | | | | | < | | | < < < < < | < < < < < < < < < < < < | > > > | | | < | < < | < < < < < < | | < > | | < | | | < < < < < | | < < < < < < < | < < < < < | | | < < < < | | | | < < < | | | | 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 | <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.5</b></li> <li>package require <b class="pkgname">fileutil::magic::rt <span class="opt">?2.0?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">::fileutil::magic::rt::></b></a></li> <li><a href="#2"><b class="cmd">::fileutil::magic::rt::<</b></a></li> <li><a href="#3"><b class="cmd">::fileutil::magic::rt::new</b> <i class="arg">chan</i> <i class="arg">named</i> <i class="arg">analyze</i></a></li> <li><a href="#4"><b class="cmd">::fileutil::magic::rt::file_start</b> <i class="arg">name</i></a></li> <li><a href="#5"><b class="cmd">::fileutil::magic::rt::emit</b> <i class="arg">msg</i></a></li> <li><a href="#6"><b class="cmd">::fileutil::magic::rt::O</b> <i class="arg">where</i></a></li> <li><a href="#7"><b class="cmd">::fileutil::magic::rt::R</b> <i class="arg">where</i></a></li> <li><a href="#8"><b class="cmd">::fileutil::magic::rt::Nv</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">compinvert</i> <i class="arg">comp</i> <i class="arg">expected</i></a></li> <li><a href="#9"><b class="cmd">::fileutil::magic::rt::N</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">testinvert</i> <i class="arg">compinvert</i> <i class="arg">mod</i> <i class="arg">mand</i> <i class="arg">comp</i> <i class="arg">expected</i></a></li> <li><a href="#10"><b class="cmd">::fileutil::magic::rt::S</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">testinvert</i> <i class="arg">mod</i> <i class="arg">mand</i> <i class="arg">comp</i> <i class="arg">val</i></a></li> <li><a href="#11"><b class="cmd">::fileutil::magic::rt::L</b> <i class="arg">newlevel</i></a></li> <li><a href="#12"><b class="cmd">::fileutil::magic::rt::I</b> <i class="arg">offset</i> <i class="arg">it</i> <i class="arg">ioi</i> <i class="arg">ioo</i> <i class="arg">iir</i> <i class="arg">io</i></a></li> <li><a href="#13"><b class="cmd">::fileutil::magic::rt::R</b> <i class="arg">offset</i></a></li> <li><a href="#14"><b class="cmd">::fileutil::magic::rt::U</b> <i class="arg">fileindex</i> <i class="arg">name</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This package provides the runtime core for file type recognition engines written in pure Tcl and is thus used by all other packages in this module such as <b class="package"><a href="filetypes.html">fileutil::magic::filetype</a></b> and the two compiler packages <b class="package"><a href="cgen.html">fileutil::magic::cgen</a></b> and <b class="package"><a href="cfront.html">fileutil::magic::cfront</a></b>.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">COMMANDS</a></h2> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::fileutil::magic::rt::></b></a></dt> <dd><p>Increment the level and perform related housekeeping</p></dd> <dt><a name="2"><b class="cmd">::fileutil::magic::rt::<</b></a></dt> <dd><p>Decrement the level and perform related housekeeping</p></dd> <dt><a name="3"><b class="cmd">::fileutil::magic::rt::new</b> <i class="arg">chan</i> <i class="arg">named</i> <i class="arg">analyze</i></a></dt> <dd><p>Create a new command which returns one description of the file each time it is called, and a code of <i class="arg">break</i> when there are no more descriptions. <i class="arg">chan</i> is the channel containing the data to describe. The channel configuration is then managed as needed. <i class="arg">named</i> is a dictionary of named tests, as generated by <b class="cmd">fileutil::magic::cfront::compile</b>. <i class="arg">test</i> is a command prefix for a routine composed of the list of commands as returned by <b class="cmd">fileutil::magic::cfront::compile</b>.</p></dd> <dt><a name="4"><b class="cmd">::fileutil::magic::rt::file_start</b> <i class="arg">name</i></a></dt> <dd><p>This command marks the start of a magic file when debugging. It returns the empty string as its result.</p></dd> <dt><a name="5"><b class="cmd">::fileutil::magic::rt::emit</b> <i class="arg">msg</i></a></dt> <dd><p>This command adds the text <i class="arg">msg</i> to the result buffer. The message may contain the following special character sequences. They will be replaced with buffered values before the message is added to the result. The command returns the empty string as its result.</p> <dl class="doctools_definitions"> <dt><b class="const">\b</b></dt> <dd><p>This sequence is removed</p></dd> <dt><b class="const">%s</b></dt> <dd><p>Replaced with the last buffered string value.</p></dd> <dt><b class="const">%ld</b></dt> <dd><p>Replaced with the last buffered numeric value.</p></dd> <dt><b class="const">%d</b></dt> <dd><p>See above.</p></dd> <dt><b class="const">${x:...?...}</b></dt> <dd><p>Substitute one string if the file is executable, and another string otherwise.</p></dd> </dl></dd> <dt><a name="6"><b class="cmd">::fileutil::magic::rt::O</b> <i class="arg">where</i></a></dt> <dd><p>Produce an offset from <i class="arg">where</i>, relative to the cursor one level up. Produce an offset from <i class="arg">where</i>, relative to the offset one level up.</p></dd> <dt><a name="8"><b class="cmd">::fileutil::magic::rt::Nv</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">compinvert</i> <i class="arg">comp</i> <i class="arg">expected</i></a></dt> <dd><p>A limited form of <b class="cmd">::fileutile::magic::rt::N</b> that only checks for equality and can't be told to invert the test.</p></dd> <dt><a name="9"><b class="cmd">::fileutil::magic::rt::N</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">testinvert</i> <i class="arg">compinvert</i> <i class="arg">mod</i> <i class="arg">mand</i> <i class="arg">comp</i> <i class="arg">expected</i></a></dt> <dd><p>Fetch the numeric value with <i class="arg">type</i> from the absolute location <i class="arg">offset</i>, compare it with <i class="arg">expected</i> using <i class="arg">comp</i> as the comparision operator, and returns the result.</p> <p>The argument <i class="arg">comp</i> must be one of Tcl's comparison operators.</p> <pre class="doctools_example"> <comp> <fetched-and-masked-value> <comp> <expected> </pre> <p>The special comparison operator <b class="const">x</b> signals that no comparison should be done, or, in other words, that the fetched value will always match <i class="arg">val</i>.</p></dd> <dt><a name="10"><b class="cmd">::fileutil::magic::rt::S</b> <i class="arg">type</i> <i class="arg">offset</i> <i class="arg">testinvert</i> <i class="arg">mod</i> <i class="arg">mand</i> <i class="arg">comp</i> <i class="arg">val</i></a></dt> <dd><p>Like <b class="cmd">::fileutil::magic::rt::N</b> except that it fetches and compares string types , not numeric data.</p></dd> <dt><a name="11"><b class="cmd">::fileutil::magic::rt::L</b> <i class="arg">newlevel</i></a></dt> <dd><p>Sets the current level in the calling context to <i class="arg">newlevel</i>. The command returns the empty string as its result.</p></dd> <dt><a name="12"><b class="cmd">::fileutil::magic::rt::I</b> <i class="arg">offset</i> <i class="arg">it</i> <i class="arg">ioi</i> <i class="arg">ioo</i> <i class="arg">iir</i> <i class="arg">io</i></a></dt> <dd><p>Calculates an offset based on an initial offset and the provided modifiers.</p></dd> <dt><a name="13"><b class="cmd">::fileutil::magic::rt::R</b> <i class="arg">offset</i></a></dt> <dd><p>Given an initial offset, calculates an offset relative to the cursor at the next level up. The cursor is the position in the data one character after the data extracted from the file one level up.</p></dd> <dt><a name="14"><b class="cmd">::fileutil::magic::rt::U</b> <i class="arg">fileindex</i> <i class="arg">name</i></a></dt> <dd><p>Add a level and use a named test script.</p></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">NUMERIC TYPES</a></h2> <dl class="doctools_definitions"> <dt><b class="const">byte</b></dt> <dd><p>8-bit integer</p></dd> <dt><b class="const">short</b></dt> |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/httpd/httpd.html.
1 2 | <!DOCTYPE html><html><head> | | | 1 2 3 4 5 6 7 8 9 10 | <!DOCTYPE html><html><head> <title>httpd - Tcl Web Server</title> <style type="text/css"><!-- HTML { background: #FFFFFF; color: black; } BODY { background: #FFFFFF; |
︙ | ︙ | |||
92 93 94 95 96 97 98 | } --></style> </head> <!-- Generated from file 'httpd.man' by tcllib/doctools with format 'html' --> <!-- Copyright &copy; 2018 Sean Woods &lt;[email protected]&gt; --> | | < < < < < < < < < | | | | > | | | | | | | | | | > > | > | | | | > > > | | | | | < < < | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | > > > > > > | | | | > | | > | | | > > | | | > > > > | | > > > > > > > | | | > > | | | | > | < | | | < < < | | | < | < < < < < < < < < < < | | | | < < | > | | < > > | | | | < < | | < < < < < < < < < < < < < < < | | > | | | | | | | > | | | | | > | | | < | | | > > > | > > > > > > > | < < | > | < < > > > > | > | | < < > > | | < > | | | | | | | < > | > | < > > > > > > > > > > > > < < < > | < | < > > > > | > > | > > > > > > > > > > | > | > > > > > | | > > > > > > > > | > > > > | > > > > > | | | | | < < | | < < < | < < < < < < < > < < | < < < < < < < < < < < < | < < > > > | < < > | < < < < < < < < < < < < < < < < < < < < < < > > | < | < | < < | < < | < < < < < < < < < < < < < < < < < < | | > > > > > > | | | | | | | > > > | | < | < > > > > > > > > > > > > > > > > | < < < < < < < < > > > > > | < > > > > | | < | | | > | < | > > | > > > > > > > > > > > > | > | < < < > | > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > | | < > > > > > | | | | > > | < > > > > > > > > > > > > > > | > | | < | > > > > > > > > | > > > | > > > > > > > > > > > > > > > > > > > | < < < > | | > > > > > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | > > > > > > > > | < | > > > > > > > | | > > > > > | > > | > > > | > > | > > | | | | 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 | } --></style> </head> <!-- Generated from file 'httpd.man' by tcllib/doctools with format 'html' --> <!-- Copyright &copy; 2018 Sean Woods &lt;[email protected]&gt; --> <!-- httpd.n --> <body><div class="doctools"> <h1 class="doctools_title">httpd(n) 4.3 httpd "Tcl Web Server"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>httpd - A TclOO and coroutine based web server</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">Minimal Example</a></li> <li class="doctools_section"><a href="#section3">Classes</a> <ul> <li class="doctools_subsection"><a href="#subsection1">Class httpd::mime</a></li> <li class="doctools_subsection"><a href="#subsection2">Class httpd::reply</a></li> <li class="doctools_subsection"><a href="#subsection3">Class httpd::server</a></li> <li class="doctools_subsection"><a href="#subsection4">Class httpd::server::dispatch</a></li> <li class="doctools_subsection"><a href="#subsection5">Class httpd::content.redirect</a></li> <li class="doctools_subsection"><a href="#subsection6">Class httpd::content.cache</a></li> <li class="doctools_subsection"><a href="#subsection7">Class httpd::content.template</a></li> <li class="doctools_subsection"><a href="#subsection8">Class httpd::content.file</a></li> <li class="doctools_subsection"><a href="#subsection9">Class httpd::content.exec</a></li> <li class="doctools_subsection"><a href="#subsection10">Class httpd::content.proxy</a></li> <li class="doctools_subsection"><a href="#subsection11">Class httpd::content.cgi</a></li> <li class="doctools_subsection"><a href="#subsection12">Class httpd::protocol.scgi</a></li> <li class="doctools_subsection"><a href="#subsection13">Class httpd::content.scgi</a></li> <li class="doctools_subsection"><a href="#subsection14">Class httpd::server.scgi</a></li> <li class="doctools_subsection"><a href="#subsection15">Class httpd::content.websocket</a></li> <li class="doctools_subsection"><a href="#subsection16">Class httpd::plugin</a></li> <li class="doctools_subsection"><a href="#subsection17">Class httpd::plugin.dict_dispatch</a></li> <li class="doctools_subsection"><a href="#subsection18">Class httpd::reply.memchan</a></li> <li class="doctools_subsection"><a href="#subsection19">Class httpd::plugin.local_memchan</a></li> </ul> </li> <li class="doctools_section"><a href="#section4">AUTHORS</a></li> <li class="doctools_section"><a href="#section5">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.6</b></li> <li>package require <b class="pkgname">httpd <span class="opt">?4.3?</span></b></li> <li>package require <b class="pkgname">uuid</b></li> <li>package require <b class="pkgname">clay</b></li> <li>package require <b class="pkgname">coroutine</b></li> <li>package require <b class="pkgname">fileutil</b></li> <li>package require <b class="pkgname">fileutil::magic::filetype</b></li> <li>package require <b class="pkgname">websocket</b></li> <li>package require <b class="pkgname">mime</b></li> <li>package require <b class="pkgname">cron</b></li> <li>package require <b class="pkgname">uri</b></li> <li>package require <b class="pkgname">Markdown</b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1">method <b class="cmd">ChannelCopy</b> <i class="arg">in</i> <i class="arg">out</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#2">method <b class="cmd">html_header</b> <span class="opt">?<i class="arg">title</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#3">method <b class="cmd">html_footer</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#4">method <b class="cmd">http_code_string</b> <i class="arg">code</i></a></li> <li><a href="#5">method <b class="cmd">HttpHeaders</b> <i class="arg">sock</i> <span class="opt">?<i class="arg">debug</i> <b class="const"></b>?</span></a></li> <li><a href="#6">method <b class="cmd">HttpHeaders_Default</b></a></li> <li><a href="#7">method <b class="cmd">HttpServerHeaders</b></a></li> <li><a href="#8">method <b class="cmd">MimeParse</b> <i class="arg">mimetext</i></a></li> <li><a href="#9">method <b class="cmd">Url_Decode</b> <i class="arg">data</i></a></li> <li><a href="#10">method <b class="cmd">Url_PathCheck</b> <i class="arg">urlsuffix</i></a></li> <li><a href="#11">method <b class="cmd">wait</b> <i class="arg">mode</i> <i class="arg">sock</i></a></li> <li><a href="#12">method <b class="cmd">constructor</b> <i class="arg">ServerObj</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#13">method <b class="cmd">destructor</b> <span class="opt">?<i class="arg">dictargs</i>?</span></a></li> <li><a href="#14">method <b class="cmd">close</b></a></li> <li><a href="#15">method <b class="cmd">Log_Dispatched</b></a></li> <li><a href="#16">method <b class="cmd">dispatch</b> <i class="arg">newsock</i> <i class="arg">datastate</i></a></li> <li><a href="#17">method <b class="cmd">Dispatch</b></a></li> <li><a href="#18">method <b class="cmd">html_css</b></a></li> <li><a href="#19">method <b class="cmd">html_header</b> <i class="arg">title</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#20">method <b class="cmd">html_footer</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#21">method <b class="cmd">error</b> <i class="arg">code</i> <span class="opt">?<i class="arg">msg</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">errorInfo</i> <b class="const"></b>?</span></a></li> <li><a href="#22">method <b class="cmd">content</b></a></li> <li><a href="#23">method <b class="cmd">EncodeStatus</b> <i class="arg">status</i></a></li> <li><a href="#24">method <b class="cmd">log</b> <i class="arg">type</i> <span class="opt">?<i class="arg">info</i> <b class="const"></b>?</span></a></li> <li><a href="#25">method <b class="cmd">CoroName</b></a></li> <li><a href="#26">method <b class="cmd">DoOutput</b></a></li> <li><a href="#27">method <b class="cmd">FormData</b></a></li> <li><a href="#28">method <b class="cmd">PostData</b> <i class="arg">length</i></a></li> <li><a href="#29">method <b class="cmd">Session_Load</b></a></li> <li><a href="#30">method <b class="cmd">TransferComplete</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#31">method <b class="cmd">puts</b> <i class="arg">line</i></a></li> <li><a href="#32">method <b class="cmd">RequestFind</b> <i class="arg">field</i></a></li> <li><a href="#33">method <b class="cmd">request</b> <i class="arg">subcommand</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#34">method <b class="cmd">reply</b> <i class="arg">subcommand</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#35">method <b class="cmd">reset</b></a></li> <li><a href="#36">method <b class="cmd">timeOutCheck</b></a></li> <li><a href="#37">method <b class="cmd">timestamp</b></a></li> <li><a href="#38">method <b class="cmd">constructor</b> <i class="arg">args</i> <span class="opt">?<i class="arg">port</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">myaddr</i> <b class="const">127.0.0.1</b>?</span> <span class="opt">?<i class="arg">string</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">name</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">doc_root</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">reverse_dns</i> <b class="const">0</b>?</span> <span class="opt">?<i class="arg">configuration_file</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">protocol</i> <b class="const">HTTP/1.1</b>?</span></a></li> <li><a href="#39">method <b class="cmd">destructor</b> <span class="opt">?<i class="arg">dictargs</i>?</span></a></li> <li><a href="#40">method <b class="cmd">connect</b> <i class="arg">sock</i> <i class="arg">ip</i> <i class="arg">port</i></a></li> <li><a href="#41">method <b class="cmd">ServerHeaders</b> <i class="arg">ip</i> <i class="arg">http_request</i> <i class="arg">mimetxt</i></a></li> <li><a href="#42">method <b class="cmd">Connect</b> <i class="arg">uuid</i> <i class="arg">sock</i> <i class="arg">ip</i></a></li> <li><a href="#43">method <b class="cmd">counter</b> <i class="arg">which</i></a></li> <li><a href="#44">method <b class="cmd">CheckTimeout</b></a></li> <li><a href="#45">method <b class="cmd">debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#46">method <b class="cmd">dispatch</b> <i class="arg">data</i></a></li> <li><a href="#47">method <b class="cmd">Dispatch_Default</b> <i class="arg">reply</i></a></li> <li><a href="#48">method <b class="cmd">Dispatch_Local</b> <i class="arg">data</i></a></li> <li><a href="#49">method <b class="cmd">Headers_Local</b> <i class="arg">varname</i></a></li> <li><a href="#50">method <b class="cmd">Headers_Process</b> <i class="arg">varname</i></a></li> <li><a href="#51">method <b class="cmd">HostName</b> <i class="arg">ipaddr</i></a></li> <li><a href="#52">method <b class="cmd">log</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#53">method <b class="cmd">plugin</b> <i class="arg">slot</i> <span class="opt">?<i class="arg">class</i> <b class="const"></b>?</span></a></li> <li><a href="#54">method <b class="cmd">port_listening</b></a></li> <li><a href="#55">method <b class="cmd">PrefixNormalize</b> <i class="arg">prefix</i></a></li> <li><a href="#56">method <b class="cmd">source</b> <i class="arg">filename</i></a></li> <li><a href="#57">method <b class="cmd">start</b></a></li> <li><a href="#58">method <b class="cmd">stop</b></a></li> <li><a href="#59">method <b class="cmd">SubObject {} db</b></a></li> <li><a href="#60">method <b class="cmd">SubObject {} default</b></a></li> <li><a href="#61">method <b class="cmd">template</b> <i class="arg">page</i></a></li> <li><a href="#62">method <b class="cmd">TemplateSearch</b> <i class="arg">page</i></a></li> <li><a href="#63">method <b class="cmd">Thread_start</b></a></li> <li><a href="#64">method <b class="cmd">Uuid_Generate</b></a></li> <li><a href="#65">method <b class="cmd">Validate_Connection</b> <i class="arg">sock</i> <i class="arg">ip</i></a></li> <li><a href="#66">method <b class="cmd">reset</b></a></li> <li><a href="#67">method <b class="cmd">content</b></a></li> <li><a href="#68">method <b class="cmd">Dispatch</b></a></li> <li><a href="#69">method <b class="cmd">content</b></a></li> <li><a href="#70">method <b class="cmd">FileName</b></a></li> <li><a href="#71">method <b class="cmd">DirectoryListing</b> <i class="arg">local_file</i></a></li> <li><a href="#72">method <b class="cmd">content</b></a></li> <li><a href="#73">method <b class="cmd">Dispatch</b></a></li> <li><a href="#74">method <b class="cmd">CgiExec</b> <i class="arg">execname</i> <i class="arg">script</i> <i class="arg">arglist</i></a></li> <li><a href="#75">method <b class="cmd">Cgi_Executable</b> <i class="arg">script</i></a></li> <li><a href="#76">method <b class="cmd">proxy_channel</b></a></li> <li><a href="#77">method <b class="cmd">proxy_path</b></a></li> <li><a href="#78">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></li> <li><a href="#79">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#80">method <b class="cmd">Dispatch</b></a></li> <li><a href="#81">method <b class="cmd">FileName</b></a></li> <li><a href="#82">method <b class="cmd">proxy_channel</b></a></li> <li><a href="#83">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></li> <li><a href="#84">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#85">method <b class="cmd">DirectoryListing</b> <i class="arg">local_file</i></a></li> <li><a href="#86">method <b class="cmd">EncodeStatus</b> <i class="arg">status</i></a></li> <li><a href="#87">method <b class="cmd">scgi_info</b></a></li> <li><a href="#88">method <b class="cmd">proxy_channel</b></a></li> <li><a href="#89">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></li> <li><a href="#90">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#91">method <b class="cmd">debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#92">method <b class="cmd">Connect</b> <i class="arg">uuid</i> <i class="arg">sock</i> <i class="arg">ip</i></a></li> <li><a href="#93">method <b class="cmd">Dispatch_Dict</b> <i class="arg">data</i></a></li> <li><a href="#94">method <b class="cmd">uri {} add</b> <i class="arg">vhosts</i> <i class="arg">patterns</i> <i class="arg">info</i></a></li> <li><a href="#95">method <b class="cmd">uri {} direct</b> <i class="arg">vhosts</i> <i class="arg">patterns</i> <i class="arg">info</i> <i class="arg">body</i></a></li> <li><a href="#96">method <b class="cmd">output</b></a></li> <li><a href="#97">method <b class="cmd">DoOutput</b></a></li> <li><a href="#98">method <b class="cmd">close</b></a></li> <li><a href="#99">method <b class="cmd">local_memchan</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#100">method <b class="cmd">Connect_Local</b> <i class="arg">uuid</i> <i class="arg">sock</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This module implements a web server, suitable for embedding in an application. The server is object oriented, and contains all of the fundamentals needed for a full service website.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">Minimal Example</a></h2> <p>Starting a web service requires starting a class of type <b class="cmd">httpd::server</b>, and providing that server with one or more URIs to service, and <b class="cmd">httpd::reply</b> derived classes to generate them.</p> <pre class="doctools_example"> tool::define ::reply.hello { method content {} { my puts "<HTML><HEAD><TITLE>IRM Dispatch Server</TITLE></HEAD><BODY>" my puts "<h1>Hello World!</h1>" my puts </BODY></HTML> } } ::docserver::server create HTTPD port 8015 myaddr 127.0.0.1 HTTPD add_uri /* [list mixin reply.hello] </pre> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Classes</a></h2> <div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Class httpd::mime</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="1">method <b class="cmd">ChannelCopy</b> <i class="arg">in</i> <i class="arg">out</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="2">method <b class="cmd">html_header</b> <span class="opt">?<i class="arg">title</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="3">method <b class="cmd">html_footer</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="4">method <b class="cmd">http_code_string</b> <i class="arg">code</i></a></dt> <dd></dd> <dt><a name="5">method <b class="cmd">HttpHeaders</b> <i class="arg">sock</i> <span class="opt">?<i class="arg">debug</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="6">method <b class="cmd">HttpHeaders_Default</b></a></dt> <dd></dd> <dt><a name="7">method <b class="cmd">HttpServerHeaders</b></a></dt> <dd></dd> <dt><a name="8">method <b class="cmd">MimeParse</b> <i class="arg">mimetext</i></a></dt> <dd><p>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 <b class="cmd">error</b> method, and immediately invoke the <b class="cmd">output</b> method to produce an error code and close the connection.</p></dd> <dt><a name="9">method <b class="cmd">Url_Decode</b> <i class="arg">data</i></a></dt> <dd><p>De-httpizes a string.</p></dd> <dt><a name="10">method <b class="cmd">Url_PathCheck</b> <i class="arg">urlsuffix</i></a></dt> <dd></dd> <dt><a name="11">method <b class="cmd">wait</b> <i class="arg">mode</i> <i class="arg">sock</i></a></dt> <dd></dd> </dl> </div> <div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">Class httpd::reply</a></h3> <p><em>ancestors</em>: <b class="class">httpd::mime</b></p> <p>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 <i class="arg">chan</i> variable. The process of generating a reply begins with an <b class="cmd">httpd::server</b> generating a <b class="cmd">http::class</b> object, mixing in a set of behaviors and then invoking the reply object's <b class="cmd">dispatch</b> method. In normal operations the <b class="cmd">dispatch</b> method:</p> <ol class="doctools_enumerated"> <li><p>Invokes the <b class="cmd">reset</b> method for the object to populate default headers.</p></li> <li><p>Invokes the <b class="cmd">HttpHeaders</b> method to stream the MIME headers out of the socket</p></li> <li><p>Invokes the <b class="cmd">request parse</b> method to convert the stream of MIME headers into a dict that can be read via the <b class="cmd">request</b> method.</p></li> <li><p>Stores the raw stream of MIME headers in the <i class="arg">rawrequest</i> variable of the object.</p></li> <li><p>Invokes the <b class="cmd">content</b> method for the object, generating an call to the <b class="cmd">error</b> method if an exception is raised.</p></li> <li><p>Invokes the <b class="cmd">output</b> method for the object</p></li> </ol> <p>Developers have the option of streaming output to a buffer via the <b class="cmd">puts</b> method of the reply, or simply populating the <i class="arg">reply_body</i> variable of the object. The information returned by the <b class="cmd">content</b> method is not interpreted in any way. If an exception is thrown (via the <b class="cmd">error</b> command in Tcl, for example) the caller will auto-generate a 500 {Internal Error} message. A typical implementation of <b class="cmd">content</b> look like:</p> <pre class="doctools_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] } } </pre> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="12">method <b class="cmd">constructor</b> <i class="arg">ServerObj</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="13">method <b class="cmd">destructor</b> <span class="opt">?<i class="arg">dictargs</i>?</span></a></dt> <dd><p>clean up on exit</p></dd> <dt><a name="14">method <b class="cmd">close</b></a></dt> <dd><p>Close channels opened by this object</p></dd> <dt><a name="15">method <b class="cmd">Log_Dispatched</b></a></dt> <dd><p>Record a dispatch event</p></dd> <dt><a name="16">method <b class="cmd">dispatch</b> <i class="arg">newsock</i> <i class="arg">datastate</i></a></dt> <dd><p>Accept the handoff from the server object of the socket <em>newsock</em> and feed it the state <em>datastate</em>. Fields the <em>datastate</em> are looking for in particular are:</p> <p>* <b class="const">mixin</b> - A key/value list of slots and classes to be mixed into the object prior to invoking <b class="cmd">Dispatch</b>.</p> <p>* <b class="const">http</b> - A key/value list of values to populate the object's <em>request</em> ensemble</p> <p>All other fields are passed along to the <b class="method">clay</b> structure of the object.</p></dd> <dt><a name="17">method <b class="cmd">Dispatch</b></a></dt> <dd></dd> <dt><a name="18">method <b class="cmd">html_css</b></a></dt> <dd></dd> <dt><a name="19">method <b class="cmd">html_header</b> <i class="arg">title</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="20">method <b class="cmd">html_footer</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="21">method <b class="cmd">error</b> <i class="arg">code</i> <span class="opt">?<i class="arg">msg</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">errorInfo</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="22">method <b class="cmd">content</b></a></dt> <dd><p>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"</p></dd> <dt><a name="23">method <b class="cmd">EncodeStatus</b> <i class="arg">status</i></a></dt> <dd><p>Formulate a standard HTTP status header from he string provided.</p></dd> <dt><a name="24">method <b class="cmd">log</b> <i class="arg">type</i> <span class="opt">?<i class="arg">info</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="25">method <b class="cmd">CoroName</b></a></dt> <dd></dd> <dt><a name="26">method <b class="cmd">DoOutput</b></a></dt> <dd><p>Generates the the HTTP reply, streams that reply back across <i class="arg">chan</i>, and destroys the object.</p></dd> <dt><a name="27">method <b class="cmd">FormData</b></a></dt> <dd><p>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 <b class="cmd">mime</b> package, including the MIME_TOKEN, which can be fed back into the mime package to read out the contents.</p></dd> <dt><a name="28">method <b class="cmd">PostData</b> <i class="arg">length</i></a></dt> <dd><p>Stream <i class="arg">length</i> bytes from the <i class="arg">chan</i> socket, but only of the request is a POST or PUSH. Returns an empty string otherwise.</p></dd> <dt><a name="29">method <b class="cmd">Session_Load</b></a></dt> <dd><p>Manage session data</p></dd> <dt><a name="30">method <b class="cmd">TransferComplete</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Intended to be invoked from <b class="cmd">chan copy</b> as a callback. This closes every channel fed to it on the command line, and then destroys the object.</p> <pre class="doctools_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 </pre> </dd> <dt><a name="31">method <b class="cmd">puts</b> <i class="arg">line</i></a></dt> <dd><p>Appends the value of <i class="arg">string</i> to the end of <i class="arg">reply_body</i>, as well as a trailing newline character.</p></dd> <dt><a name="32">method <b class="cmd">RequestFind</b> <i class="arg">field</i></a></dt> <dd></dd> <dt><a name="33">method <b class="cmd">request</b> <i class="arg">subcommand</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="34">method <b class="cmd">reply</b> <i class="arg">subcommand</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="35">method <b class="cmd">reset</b></a></dt> <dd><p>Clear the contents of the <i class="arg">reply_body</i> variable, and reset all headers in the <b class="cmd">reply</b> structure back to the defaults for this object.</p></dd> <dt><a name="36">method <b class="cmd">timeOutCheck</b></a></dt> <dd><p>Called from the <b class="cmd">http::server</b> 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 <i class="arg">chan</i> socket.</p></dd> <dt><a name="37">method <b class="cmd">timestamp</b></a></dt> <dd><p>Return the current system time in the format:</p> <pre class="doctools_example">%a, %d %b %Y %T %Z</pre> </dd> </dl> </div> <div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Class httpd::server</a></h3> <p><em>ancestors</em>: <b class="class">httpd::mime</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="38">method <b class="cmd">constructor</b> <i class="arg">args</i> <span class="opt">?<i class="arg">port</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">myaddr</i> <b class="const">127.0.0.1</b>?</span> <span class="opt">?<i class="arg">string</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">name</i> <b class="const">auto</b>?</span> <span class="opt">?<i class="arg">doc_root</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">reverse_dns</i> <b class="const">0</b>?</span> <span class="opt">?<i class="arg">configuration_file</i> <b class="const"></b>?</span> <span class="opt">?<i class="arg">protocol</i> <b class="const">HTTP/1.1</b>?</span></a></dt> <dd></dd> <dt><a name="39">method <b class="cmd">destructor</b> <span class="opt">?<i class="arg">dictargs</i>?</span></a></dt> <dd></dd> <dt><a name="40">method <b class="cmd">connect</b> <i class="arg">sock</i> <i class="arg">ip</i> <i class="arg">port</i></a></dt> <dd><p>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 <b class="cmd">Connect</b> method.</p></dd> <dt><a name="41">method <b class="cmd">ServerHeaders</b> <i class="arg">ip</i> <i class="arg">http_request</i> <i class="arg">mimetxt</i></a></dt> <dd></dd> <dt><a name="42">method <b class="cmd">Connect</b> <i class="arg">uuid</i> <i class="arg">sock</i> <i class="arg">ip</i></a></dt> <dd><p>This method reads HTTP headers, and then consults the <b class="cmd">dispatch</b> method to determine if the request is valid, and/or what kind of reply to generate. Under normal cases, an object of class <b class="cmd">::http::reply</b> is created, and that class's <b class="cmd">dispatch</b> 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.</p></dd> <dt><a name="43">method <b class="cmd">counter</b> <i class="arg">which</i></a></dt> <dd><p>Increment an internal counter.</p></dd> <dt><a name="44">method <b class="cmd">CheckTimeout</b></a></dt> <dd><p>Check open connections for a time out event.</p></dd> <dt><a name="45">method <b class="cmd">debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="46">method <b class="cmd">dispatch</b> <i class="arg">data</i></a></dt> <dd><p>Given a key/value list of information, return a data structure describing how the server should reply.</p></dd> <dt><a name="47">method <b class="cmd">Dispatch_Default</b> <i class="arg">reply</i></a></dt> <dd><p>Method dispatch method of last resort before returning a 404 NOT FOUND error. The default behavior is to look for a file in <em>DOCUMENT_ROOT</em> which matches the query.</p></dd> <dt><a name="48">method <b class="cmd">Dispatch_Local</b> <i class="arg">data</i></a></dt> <dd><p>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.</p></dd> <dt><a name="49">method <b class="cmd">Headers_Local</b> <i class="arg">varname</i></a></dt> <dd><p>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.</p></dd> <dt><a name="50">method <b class="cmd">Headers_Process</b> <i class="arg">varname</i></a></dt> <dd><p>Introspect and possibly modify a data structure destined for a reply. This method is built dynamically by the <b class="cmd">plugin</b> method.</p></dd> <dt><a name="51">method <b class="cmd">HostName</b> <i class="arg">ipaddr</i></a></dt> <dd><p>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 <em>dns</em> module from tcllib.</p></dd> <dt><a name="52">method <b class="cmd">log</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>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.</p></dd> <dt><a name="53">method <b class="cmd">plugin</b> <i class="arg">slot</i> <span class="opt">?<i class="arg">class</i> <b class="const"></b>?</span></a></dt> <dd><p>Incorporate behaviors from a plugin. This method dynamically rebuilds the <b class="cmd">Dispatch</b> and <b class="cmd">Headers</b> method. For every plugin, the server looks for the following entries in <em>clay plugin/</em>:</p> <p><em>load</em> - A script to invoke in the server's namespace during the <b class="cmd">plugin</b> method invokation.</p> <p><em>dispatch</em> - A script to stitch into the server's <b class="cmd">Dispatch</b> method.</p> <p><em>headers</em> - A script to stitch into the server's <b class="cmd">Headers</b> method.</p> <p><em>thread</em> - A script to stitch into the server's <b class="cmd">Thread_start</b> method.</p></dd> <dt><a name="54">method <b class="cmd">port_listening</b></a></dt> <dd><p>Return the actual port that httpd is listening on.</p></dd> <dt><a name="55">method <b class="cmd">PrefixNormalize</b> <i class="arg">prefix</i></a></dt> <dd><p>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.</p></dd> <dt><a name="56">method <b class="cmd">source</b> <i class="arg">filename</i></a></dt> <dd></dd> <dt><a name="57">method <b class="cmd">start</b></a></dt> <dd><p>Open the socket listener.</p></dd> <dt><a name="58">method <b class="cmd">stop</b></a></dt> <dd><p>Shut off the socket listener, and destroy any pending replies.</p></dd> <dt><a name="59">method <b class="cmd">SubObject {} db</b></a></dt> <dd></dd> <dt><a name="60">method <b class="cmd">SubObject {} default</b></a></dt> <dd></dd> <dt><a name="61">method <b class="cmd">template</b> <i class="arg">page</i></a></dt> <dd><p>Return a template for the string <i class="arg">page</i></p></dd> <dt><a name="62">method <b class="cmd">TemplateSearch</b> <i class="arg">page</i></a></dt> <dd><p>Perform a search for the template that best matches <i class="arg">page</i>. 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 <span class="opt">?doc_root?</span> directory.</p></dd> <dt><a name="63">method <b class="cmd">Thread_start</b></a></dt> <dd><p>Built by the <b class="cmd">plugin</b> method. Called by the <b class="cmd">start</b> method. Intended to allow plugins to spawn worker threads.</p></dd> <dt><a name="64">method <b class="cmd">Uuid_Generate</b></a></dt> <dd><p>Generate a GUUID. Used to ensure every request has a unique ID. The default implementation is:</p> <pre class="doctools_example"> return [::uuid::uuid generate] </pre> </dd> <dt><a name="65">method <b class="cmd">Validate_Connection</b> <i class="arg">sock</i> <i class="arg">ip</i></a></dt> <dd><p>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.</p></dd> </dl> </div> <div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Class httpd::server::dispatch</a></h3> <p><em>ancestors</em>: <b class="class">httpd::server</b></p> <p>Provide a backward compadible alias</p> </div> <div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Class httpd::content.redirect</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="66">method <b class="cmd">reset</b></a></dt> <dd></dd> <dt><a name="67">method <b class="cmd">content</b></a></dt> <dd></dd> </dl> </div> <div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Class httpd::content.cache</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="68">method <b class="cmd">Dispatch</b></a></dt> <dd></dd> </dl> </div> <div id="subsection7" class="doctools_subsection"><h3><a name="subsection7">Class httpd::content.template</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="69">method <b class="cmd">content</b></a></dt> <dd></dd> </dl> </div> <div id="subsection8" class="doctools_subsection"><h3><a name="subsection8">Class httpd::content.file</a></h3> <p>Class to deliver Static content When utilized, this class is fed a local filename by the dispatcher</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="70">method <b class="cmd">FileName</b></a></dt> <dd></dd> <dt><a name="71">method <b class="cmd">DirectoryListing</b> <i class="arg">local_file</i></a></dt> <dd></dd> <dt><a name="72">method <b class="cmd">content</b></a></dt> <dd></dd> <dt><a name="73">method <b class="cmd">Dispatch</b></a></dt> <dd></dd> </dl> </div> <div id="subsection9" class="doctools_subsection"><h3><a name="subsection9">Class httpd::content.exec</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="74">method <b class="cmd">CgiExec</b> <i class="arg">execname</i> <i class="arg">script</i> <i class="arg">arglist</i></a></dt> <dd></dd> <dt><a name="75">method <b class="cmd">Cgi_Executable</b> <i class="arg">script</i></a></dt> <dd></dd> </dl> </div> <div id="subsection10" class="doctools_subsection"><h3><a name="subsection10">Class httpd::content.proxy</a></h3> <p><em>ancestors</em>: <b class="class">httpd::content.exec</b></p> <p>Return data from an proxy process</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="76">method <b class="cmd">proxy_channel</b></a></dt> <dd></dd> <dt><a name="77">method <b class="cmd">proxy_path</b></a></dt> <dd></dd> <dt><a name="78">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></dt> <dd></dd> <dt><a name="79">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="80">method <b class="cmd">Dispatch</b></a></dt> <dd></dd> </dl> </div> <div id="subsection11" class="doctools_subsection"><h3><a name="subsection11">Class httpd::content.cgi</a></h3> <p><em>ancestors</em>: <b class="class">httpd::content.proxy</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="81">method <b class="cmd">FileName</b></a></dt> <dd></dd> <dt><a name="82">method <b class="cmd">proxy_channel</b></a></dt> <dd></dd> <dt><a name="83">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></dt> <dd></dd> <dt><a name="84">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="85">method <b class="cmd">DirectoryListing</b> <i class="arg">local_file</i></a></dt> <dd><p>For most CGI applications a directory list is vorboten</p></dd> </dl> </div> <div id="subsection12" class="doctools_subsection"><h3><a name="subsection12">Class httpd::protocol.scgi</a></h3> <p>Return data from an SCGI process</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="86">method <b class="cmd">EncodeStatus</b> <i class="arg">status</i></a></dt> <dd></dd> </dl> </div> <div id="subsection13" class="doctools_subsection"><h3><a name="subsection13">Class httpd::content.scgi</a></h3> <p><em>ancestors</em>: <b class="class">httpd::content.proxy</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="87">method <b class="cmd">scgi_info</b></a></dt> <dd></dd> <dt><a name="88">method <b class="cmd">proxy_channel</b></a></dt> <dd></dd> <dt><a name="89">method <b class="cmd">ProxyRequest</b> <i class="arg">chana</i> <i class="arg">chanb</i></a></dt> <dd></dd> <dt><a name="90">method <b class="cmd">ProxyReply</b> <i class="arg">chana</i> <i class="arg">chanb</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection14" class="doctools_subsection"><h3><a name="subsection14">Class httpd::server.scgi</a></h3> <p><em>ancestors</em>: <b class="class">httpd::server</b></p> <p>Act as an SCGI Server</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="91">method <b class="cmd">debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="92">method <b class="cmd">Connect</b> <i class="arg">uuid</i> <i class="arg">sock</i> <i class="arg">ip</i></a></dt> <dd></dd> </dl> </div> <div id="subsection15" class="doctools_subsection"><h3><a name="subsection15">Class httpd::content.websocket</a></h3> <p>Upgrade a connection to a websocket</p> </div> <div id="subsection16" class="doctools_subsection"><h3><a name="subsection16">Class httpd::plugin</a></h3> <p>httpd plugin template</p> </div> <div id="subsection17" class="doctools_subsection"><h3><a name="subsection17">Class httpd::plugin.dict_dispatch</a></h3> <p>A rudimentary plugin that dispatches URLs from a dict data structure</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="93">method <b class="cmd">Dispatch_Dict</b> <i class="arg">data</i></a></dt> <dd><p>Implementation of the dispatcher</p></dd> <dt><a name="94">method <b class="cmd">uri {} add</b> <i class="arg">vhosts</i> <i class="arg">patterns</i> <i class="arg">info</i></a></dt> <dd></dd> <dt><a name="95">method <b class="cmd">uri {} direct</b> <i class="arg">vhosts</i> <i class="arg">patterns</i> <i class="arg">info</i> <i class="arg">body</i></a></dt> <dd></dd> </dl> </div> <div id="subsection18" class="doctools_subsection"><h3><a name="subsection18">Class httpd::reply.memchan</a></h3> <p><em>ancestors</em>: <b class="class">httpd::reply</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="96">method <b class="cmd">output</b></a></dt> <dd></dd> <dt><a name="97">method <b class="cmd">DoOutput</b></a></dt> <dd></dd> <dt><a name="98">method <b class="cmd">close</b></a></dt> <dd></dd> </dl> </div> <div id="subsection19" class="doctools_subsection"><h3><a name="subsection19">Class httpd::plugin.local_memchan</a></h3> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="99">method <b class="cmd">local_memchan</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="100">method <b class="cmd">Connect_Local</b> <i class="arg">uuid</i> <i class="arg">sock</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>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</p></dd> </dl> </div> </div> <div id="section4" class="doctools_section"><h2><a name="section4">AUTHORS</a></h2> <p>Sean Woods</p> </div> <div id="section5" class="doctools_section"><h2><a name="section5">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>network</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. Please also report any ideas for enhancements you may have for either package and/or documentation.</p> <p>When proposing code changes, please provide <em>unified diffs</em>, i.e the output of <b class="const">diff -u</b>.</p> <p>Note further that <em>attachments</em> are strongly preferred over inlined patches. Attachments can be made by going to the <b class="const">Edit</b> form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p>TclOO, WWW, http, httpd, httpserver, services</p> </div> <div id="category" class="doctools_section"><h2><a name="category">Category</a></h2> <p>Networking</p> </div> <div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> <p>Copyright © 2018 Sean Woods <[email protected]></p> </div> </div></body></html> |
Changes to idoc/www/tcllib/files/modules/log/log.html.
︙ | ︙ | |||
233 234 235 236 237 238 239 | <dd><p>Compares two levels (including unique abbreviations) with respect to their priority. This command can be used by the -command option of lsort. The result is one of -1, 0 or 1 or an error. A result of -1 signals that level1 is of less priority than level2. 0 signals that both levels have the same priority. 1 signals that level1 has higher priority than level2.</p></dd> <dt><a name="8"><b class="cmd">::log::lvSuppress</b> <i class="arg">level</i> {<i class="arg">suppress</i> 1}</a></dt> | < | < | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | <dd><p>Compares two levels (including unique abbreviations) with respect to their priority. This command can be used by the -command option of lsort. The result is one of -1, 0 or 1 or an error. A result of -1 signals that level1 is of less priority than level2. 0 signals that both levels have the same priority. 1 signals that level1 has higher priority than level2.</p></dd> <dt><a name="8"><b class="cmd">::log::lvSuppress</b> <i class="arg">level</i> {<i class="arg">suppress</i> 1}</a></dt> <dd><p>(Un)suppresses the output of messages having the specified level. Unique abbreviations for the level are allowed here too.</p></dd> <dt><a name="9"><b class="cmd">::log::lvSuppressLE</b> <i class="arg">level</i> {<i class="arg">suppress</i> 1}</a></dt> <dd><p>(Un)suppresses the output of messages having the specified level or one of lesser priority. Unique abbreviations for the level are allowed here too.</p></dd> <dt><a name="10"><b class="cmd">::log::lvIsSuppressed</b> <i class="arg">level</i></a></dt> <dd><p>Asks the package whether the specified level is currently suppressed. Unique abbreviations of level names are allowed.</p></dd> <dt><a name="11"><b class="cmd">::log::lvCmd</b> <i class="arg">level</i> <i class="arg">cmd</i></a></dt> <dd><p>Defines for the specified level with which command to write the |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/math/math_geometry.html.
︙ | ︙ | |||
207 208 209 210 211 212 213 | <li><p><em>polyline</em> - a list of an even number of coordinates, interpreted as the x- and y-coordinates of an ordered set of points.</p></li> <li><p><em>polygon</em> - like a polyline, but the implicit assumption is that the polyline is closed (if the first and last points do not coincide, the missing segment is automatically added).</p></li> <li><p><em>point set</em> - again a list of an even number of coordinates, but the points are regarded without any ordering.</p></li> | | | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | <li><p><em>polyline</em> - a list of an even number of coordinates, interpreted as the x- and y-coordinates of an ordered set of points.</p></li> <li><p><em>polygon</em> - like a polyline, but the implicit assumption is that the polyline is closed (if the first and last points do not coincide, the missing segment is automatically added).</p></li> <li><p><em>point set</em> - again a list of an even number of coordinates, but the points are regarded without any ordering.</p></li> <li><p><em>circle</em> - a list of three numbers, the first two are the coordinates of the centre and the third is the radius.</p></li> </ul> </div> <div id="section2" class="doctools_section"><h2><a name="section2">PROCEDURES</a></h2> <p>The package defines the following public procedures:</p> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::math::geometry::+</b> <i class="arg">point1</i> <i class="arg">point2</i></a></dt> |
︙ | ︙ | |||
591 592 593 594 595 596 597 | <dd><p>Line to be checked</p></dd> <dt>list <i class="arg">circle</i></dt> <dd><p>Circle that may or may not be intersected</p></dd> </dl></dd> <dt><a name="47"><b class="cmd">::math::geometry::intersectionCircleWithCircle</b> <i class="arg">circle1</i> <i class="arg">circle2</i></a></dt> <dd><p>Determine the points at which the given two circles intersect. There can be zero, one or two points. (If the two circles touch the circle or are very close, | | | | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | <dd><p>Line to be checked</p></dd> <dt>list <i class="arg">circle</i></dt> <dd><p>Circle that may or may not be intersected</p></dd> </dl></dd> <dt><a name="47"><b class="cmd">::math::geometry::intersectionCircleWithCircle</b> <i class="arg">circle1</i> <i class="arg">circle2</i></a></dt> <dd><p>Determine the points at which the given two circles intersect. There can be zero, one or two points. (If the two circles touch the circle or are very close, then one point is returned. An arbitrary margin of 1.0e-10 times the mean of the radii of the two circles is used to determine this situation.)</p> <dl class="doctools_arguments"> <dt>list <i class="arg">circle1</i></dt> <dd><p>First circle</p></dd> <dt>list <i class="arg">circle2</i></dt> <dd><p>Second circle</p></dd> </dl></dd> <dt><a name="48"><b class="cmd">::math::geometry::tangentLinesToCircle</b> <i class="arg">point</i> <i class="arg">circle</i></a></dt> |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/math/numtheory.html.
1 2 3 4 5 6 7 | <!DOCTYPE html><html><head> <title>math::numtheory - Tcl Math Library</title> <style type="text/css"><!-- HTML { background: #FFFFFF; color: black; } | > | 1 2 3 4 5 6 7 8 | <!DOCTYPE html><html><head> <title>math::numtheory - Tcl Math Library</title> <style type="text/css"><!-- HTML { background: #FFFFFF; color: black; } |
︙ | ︙ | |||
103 104 105 106 107 108 109 | | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> | | | > > | | | | | | | | | | | | 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 | | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> <h1 class="doctools_title">math::numtheory(n) 1.1.1 tcllib "Tcl Math Library"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>math::numtheory - Number Theory</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl <span class="opt">?8.5?</span></b></li> <li>package require <b class="pkgname">math::numtheory <span class="opt">?1.1.1?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">math::numtheory::isprime</b> <i class="arg">N</i> <span class="opt">?<i class="arg">option</i> <i class="arg">value</i> ...?</span></a></li> <li><a href="#2"><b class="cmd">math::numtheory::firstNprimes</b> <i class="arg">N</i></a></li> <li><a href="#3"><b class="cmd">math::numtheory::primesLowerThan</b> <i class="arg">N</i></a></li> <li><a href="#4"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></li> <li><a href="#5"><b class="cmd">math::numtheory::primesLowerThan</b> <i class="arg">N</i></a></li> <li><a href="#6"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></li> <li><a href="#7"><b class="cmd">math::numtheory::uniquePrimeFactors</b> <i class="arg">N</i></a></li> <li><a href="#8"><b class="cmd">math::numtheory::factors</b> <i class="arg">N</i></a></li> <li><a href="#9"><b class="cmd">math::numtheory::totient</b> <i class="arg">N</i></a></li> <li><a href="#10"><b class="cmd">math::numtheory::moebius</b> <i class="arg">N</i></a></li> <li><a href="#11"><b class="cmd">math::numtheory::legendre</b> <i class="arg">a</i> <i class="arg">p</i></a></li> <li><a href="#12"><b class="cmd">math::numtheory::jacobi</b> <i class="arg">a</i> <i class="arg">b</i></a></li> <li><a href="#13"><b class="cmd">math::numtheory::gcd</b> <i class="arg">m</i> <i class="arg">n</i></a></li> <li><a href="#14"><b class="cmd">math::numtheory::lcm</b> <i class="arg">m</i> <i class="arg">n</i></a></li> <li><a href="#15"><b class="cmd">math::numtheory::numberPrimesGauss</b> <i class="arg">N</i></a></li> <li><a href="#16"><b class="cmd">math::numtheory::numberPrimesLegendre</b> <i class="arg">N</i></a></li> <li><a href="#17"><b class="cmd">math::numtheory::numberPrimesLegendreModified</b> <i class="arg">N</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This package is for collecting various number-theoretic operations, with a slight bias to prime numbers.</p> <dl class="doctools_definitions"> |
︙ | ︙ | |||
192 193 194 195 196 197 198 | </dl></dd> <dt><a name="4"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of the prime numbers in the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> | > > > > > > > > > > > > | | | | | | | | | | | | 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 | </dl></dd> <dt><a name="4"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of the prime numbers in the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> <dt><a name="5"><b class="cmd">math::numtheory::primesLowerThan</b> <i class="arg">N</i></a></dt> <dd><p>Return the prime numbers lower/equal to N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Maximum number to consider</p></dd> </dl></dd> <dt><a name="6"><b class="cmd">math::numtheory::primeFactors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of the prime numbers in the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> <dt><a name="7"><b class="cmd">math::numtheory::uniquePrimeFactors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of the <em>unique</em> prime numbers in the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> <dt><a name="8"><b class="cmd">math::numtheory::factors</b> <i class="arg">N</i></a></dt> <dd><p>Return a list of all <em>unique</em> factors in the number N, including 1 and N itself</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number to be factorised</p></dd> </dl></dd> <dt><a name="9"><b class="cmd">math::numtheory::totient</b> <i class="arg">N</i></a></dt> <dd><p>Evaluate the Euler totient function for the number N (number of numbers relatively prime to N)</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> <dt><a name="10"><b class="cmd">math::numtheory::moebius</b> <i class="arg">N</i></a></dt> <dd><p>Evaluate the Moebius function for the number N</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> <dt><a name="11"><b class="cmd">math::numtheory::legendre</b> <i class="arg">a</i> <i class="arg">p</i></a></dt> <dd><p>Evaluate the Legendre symbol (a/p)</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">a</i> (in)</dt> <dd><p>Upper number in the symbol</p></dd> <dt>integer <i class="arg">p</i> (in)</dt> <dd><p>Lower number in the symbol (must be non-zero)</p></dd> </dl></dd> <dt><a name="12"><b class="cmd">math::numtheory::jacobi</b> <i class="arg">a</i> <i class="arg">b</i></a></dt> <dd><p>Evaluate the Jacobi symbol (a/b)</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">a</i> (in)</dt> <dd><p>Upper number in the symbol</p></dd> <dt>integer <i class="arg">b</i> (in)</dt> <dd><p>Lower number in the symbol (must be odd)</p></dd> </dl></dd> <dt><a name="13"><b class="cmd">math::numtheory::gcd</b> <i class="arg">m</i> <i class="arg">n</i></a></dt> <dd><p>Return the greatest common divisor of <i class="term">m</i> and <i class="term">n</i></p> <dl class="doctools_arguments"> <dt>integer <i class="arg">m</i> (in)</dt> <dd><p>First number</p></dd> <dt>integer <i class="arg">n</i> (in)</dt> <dd><p>Second number</p></dd> </dl></dd> <dt><a name="14"><b class="cmd">math::numtheory::lcm</b> <i class="arg">m</i> <i class="arg">n</i></a></dt> <dd><p>Return the lowest common multiple of <i class="term">m</i> and <i class="term">n</i></p> <dl class="doctools_arguments"> <dt>integer <i class="arg">m</i> (in)</dt> <dd><p>First number</p></dd> <dt>integer <i class="arg">n</i> (in)</dt> <dd><p>Second number</p></dd> </dl></dd> <dt><a name="15"><b class="cmd">math::numtheory::numberPrimesGauss</b> <i class="arg">N</i></a></dt> <dd><p>Estimate the number of primes according the formula by Gauss.</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> <dt><a name="16"><b class="cmd">math::numtheory::numberPrimesLegendre</b> <i class="arg">N</i></a></dt> <dd><p>Estimate the number of primes according the formula by Legendre.</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> <dt><a name="17"><b class="cmd">math::numtheory::numberPrimesLegendreModified</b> <i class="arg">N</i></a></dt> <dd><p>Estimate the number of primes according the modified formula by Legendre.</p> <dl class="doctools_arguments"> <dt>integer <i class="arg">N</i> (in)</dt> <dd><p>Number in question</p></dd> </dl></dd> </dl> </div> |
︙ | ︙ |
Added idoc/www/tcllib/files/modules/math/trig.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | <!DOCTYPE html><html><head> <title>math::trig - Tcl Math Library</title> <style type="text/css"><!-- HTML { background: #FFFFFF; color: black; } BODY { background: #FFFFFF; color: black; } DIV.doctools { margin-left: 10%; margin-right: 10%; } DIV.doctools H1,DIV.doctools H2 { margin-left: -5%; } H1, H2, H3, H4 { margin-top: 1em; font-family: sans-serif; font-size: large; color: #005A9C; background: transparent; text-align: left; } H1.doctools_title { text-align: center; } UL,OL { margin-right: 0em; margin-top: 3pt; margin-bottom: 3pt; } UL LI { list-style: disc; } OL LI { list-style: decimal; } DT { padding-top: 1ex; } UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL { font: normal 12pt/14pt sans-serif; list-style: none; } LI.doctools_section, LI.doctools_subsection { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } PRE { display: block; font-family: monospace; white-space: pre; margin: 0%; padding-top: 0.5ex; padding-bottom: 0.5ex; padding-left: 1ex; padding-right: 1ex; width: 100%; } PRE.doctools_example { color: black; background: #f5dcb3; border: 1px solid black; } UL.doctools_requirements LI, UL.doctools_syntax LI { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } DIV.doctools_synopsis { color: black; background: #80ffff; border: 1px solid black; font-family: serif; margin-top: 1em; margin-bottom: 1em; } UL.doctools_syntax { margin-top: 1em; border-top: 1px solid black; } UL.doctools_requirements { margin-bottom: 1em; border-bottom: 1px solid black; } --></style> </head> <!-- Generated from file 'trig.man' by tcllib/doctools with format 'html' --> <!-- Copyright &copy; 2018 Arjen Markus --> <!-- math::trig.n --> <body><hr> [ <a href="../../../../../../../../home">Tcllib Home</a> | <a href="../../../../toc.html">Main Table Of Contents</a> | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> <h1 class="doctools_title">math::trig(n) 1.0.0 tcllib "Tcl Math Library"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>math::trig - Trigonometric anf hyperbolic functions</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">FUNCTIONS</a></li> <li class="doctools_section"><a href="#section3">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.5</b></li> <li>package require <b class="pkgname">math::trig 1.0.0</b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">::math::trig::radian_reduced</b> <i class="arg">angle</i></a></li> <li><a href="#2"><b class="cmd">::math::trig::degree_reduced</b> <i class="arg">angle</i></a></li> <li><a href="#3"><b class="cmd">::math::trig::cosec</b> <i class="arg">angle</i></a></li> <li><a href="#4"><b class="cmd">::math::trig::sec</b> <i class="arg">angle</i></a></li> <li><a href="#5"><b class="cmd">::math::trig::cotan</b> <i class="arg">angle</i></a></li> <li><a href="#6"><b class="cmd">::math::trig::acosec</b> <i class="arg">value</i></a></li> <li><a href="#7"><b class="cmd">::math::trig::asec</b> <i class="arg">value</i></a></li> <li><a href="#8"><b class="cmd">::math::trig::acotan</b> <i class="arg">value</i></a></li> <li><a href="#9"><b class="cmd">::math::trig::cosech</b> <i class="arg">value</i></a></li> <li><a href="#10"><b class="cmd">::math::trig::sech</b> <i class="arg">value</i></a></li> <li><a href="#11"><b class="cmd">::math::trig::cotanh</b> <i class="arg">value</i></a></li> <li><a href="#12"><b class="cmd">::math::trig::asinh</b> <i class="arg">value</i></a></li> <li><a href="#13"><b class="cmd">::math::trig::acosh</b> <i class="arg">value</i></a></li> <li><a href="#14"><b class="cmd">::math::trig::atanh</b> <i class="arg">value</i></a></li> <li><a href="#15"><b class="cmd">::math::trig::acosech</b> <i class="arg">value</i></a></li> <li><a href="#16"><b class="cmd">::math::trig::asech</b> <i class="arg">value</i></a></li> <li><a href="#17"><b class="cmd">::math::trig::acotanh</b> <i class="arg">value</i></a></li> <li><a href="#18"><b class="cmd">::math::trig::sind</b> <i class="arg">angle</i></a></li> <li><a href="#19"><b class="cmd">::math::trig::cosd</b> <i class="arg">angle</i></a></li> <li><a href="#20"><b class="cmd">::math::trig::tand</b> <i class="arg">angle</i></a></li> <li><a href="#21"><b class="cmd">::math::trig::cosecd</b> <i class="arg">angle</i></a></li> <li><a href="#22"><b class="cmd">::math::trig::secd</b> <i class="arg">angle</i></a></li> <li><a href="#23"><b class="cmd">::math::trig::cotand</b> <i class="arg">angle</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>The <i class="term">math::trig</i> package defines a set of trigonomic and hyperbolic functions and their inverses. In addition it defines versions of the trigonomic functions that take arguments in degrees instead of radians.</p> <p>For easy use these functions may be imported into the <i class="term">tcl::mathfunc</i> namespace, so that they can be used directly in the <i class="term">expr</i> command.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">FUNCTIONS</a></h2> <p>The functions <i class="term">radian_reduced</i> and <i class="term">degree_reduced</i> return a reduced angle, in respectively radians and degrees, in the intervals [0, 2pi) and [0, 360):</p> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">::math::trig::radian_reduced</b> <i class="arg">angle</i></a></dt> <dd><p>Return the equivalent angle in the interval [0, 2pi).</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> <dt><a name="2"><b class="cmd">::math::trig::degree_reduced</b> <i class="arg">angle</i></a></dt> <dd><p>Return the equivalent angle in the interval [0, 360).</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> </dl> <p>The following trigonomic functions are defined in addition to the ones defined in the <i class="term">expr</i> command:</p> <dl class="doctools_definitions"> <dt><a name="3"><b class="cmd">::math::trig::cosec</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cosecant of the angle (1/cos(angle))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> <dt><a name="4"><b class="cmd">::math::trig::sec</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the secant of the angle (1/sin(angle))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> <dt><a name="5"><b class="cmd">::math::trig::cotan</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cotangent of the angle (1/tan(angle))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> </dl> <p>For these functions also the inverses are defined:</p> <dl class="doctools_definitions"> <dt><a name="6"><b class="cmd">::math::trig::acosec</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc cosecant of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="7"><b class="cmd">::math::trig::asec</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc secant of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="8"><b class="cmd">::math::trig::acotan</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc cotangent of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> </dl> <p>The following hyperbolic and inverse hyperbolic functions are defined:</p> <dl class="doctools_definitions"> <dt><a name="9"><b class="cmd">::math::trig::cosech</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the hyperbolic cosecant of the value (1/sinh(value))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="10"><b class="cmd">::math::trig::sech</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the hyperbolic secant of the value (1/cosh(value))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="11"><b class="cmd">::math::trig::cotanh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the hyperbolic cotangent of the value (1/tanh(value))</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="12"><b class="cmd">::math::trig::asinh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic sine of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="13"><b class="cmd">::math::trig::acosh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic cosine of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="14"><b class="cmd">::math::trig::atanh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic tangent of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="15"><b class="cmd">::math::trig::acosech</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic cosecant of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="16"><b class="cmd">::math::trig::asech</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic secant of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> <dt><a name="17"><b class="cmd">::math::trig::acotanh</b> <i class="arg">value</i></a></dt> <dd><p>Calculate the arc hyperbolic cotangent of the value</p> <dl class="doctools_arguments"> <dt>float <i class="arg">value</i></dt> <dd><p>Value of the argument</p></dd> </dl></dd> </dl> <p>The following versions of the common trigonometric functions and their inverses are defined:</p> <dl class="doctools_definitions"> <dt><a name="18"><b class="cmd">::math::trig::sind</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the sine of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> <dt><a name="19"><b class="cmd">::math::trig::cosd</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cosine of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in radians)</p></dd> </dl></dd> <dt><a name="20"><b class="cmd">::math::trig::tand</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cotangent of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> <dt><a name="21"><b class="cmd">::math::trig::cosecd</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cosecant of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> <dt><a name="22"><b class="cmd">::math::trig::secd</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the secant of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> <dt><a name="23"><b class="cmd">::math::trig::cotand</b> <i class="arg">angle</i></a></dt> <dd><p>Calculate the cotangent of the angle (in degrees)</p> <dl class="doctools_arguments"> <dt>float <i class="arg">angle</i></dt> <dd><p>Angle (in degrees)</p></dd> </dl></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>math :: trig</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. Please also report any ideas for enhancements you may have for either package and/or documentation.</p> <p>When proposing code changes, please provide <em>unified diffs</em>, i.e the output of <b class="const">diff -u</b>.</p> <p>Note further that <em>attachments</em> are strongly preferred over inlined patches. Attachments can be made by going to the <b class="const">Edit</b> form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p><a href="../../../../index.html#math">math</a>, <a href="../../../../index.html#trigonometry">trigonometry</a></p> </div> <div id="category" class="doctools_section"><h2><a name="category">Category</a></h2> <p>Mathematics</p> </div> <div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> <p>Copyright © 2018 Arjen Markus</p> </div> </div></body></html> |
Changes to idoc/www/tcllib/files/modules/nns/nns_client.html.
︙ | ︙ | |||
228 229 230 231 232 233 234 | be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="8"><b class="cmd">::nameserv::configure</b></a></dt> <dd><p>In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="9"><b class="cmd">::nameserv::configure</b> <b class="option">-option</b></a></dt> <dd><p>In this form the command is an alias for | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="8"><b class="cmd">::nameserv::configure</b></a></dt> <dd><p>In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="9"><b class="cmd">::nameserv::configure</b> <b class="option">-option</b></a></dt> <dd><p>In this form the command is an alias for "<b class="cmd">::nameserv::cget</b> <b class="option">-option</b>". The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section5">OPTIONS</a></span>.</p></dd> <dt><a name="10"><b class="cmd">::nameserv::configure</b> <b class="option">-option</b> <i class="arg">value</i>...</a></dt> <dd><p>In this form the command is used to configure one or more of the supported options. At least one option has to be specified, and each option is followed by its new value. The list of supported options and their meaning can be found in |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/nns/nns_server.html.
︙ | ︙ | |||
183 184 185 186 187 188 189 | be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="5"><b class="cmd">::nameserv::server::configure</b></a></dt> <dd><p>In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="6"><b class="cmd">::nameserv::server::configure</b> <b class="option">-option</b></a></dt> <dd><p>In this form the command is an alias for | | | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="5"><b class="cmd">::nameserv::server::configure</b></a></dt> <dd><p>In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="6"><b class="cmd">::nameserv::server::configure</b> <b class="option">-option</b></a></dt> <dd><p>In this form the command is an alias for "<b class="cmd">::nameserv::server::cget</b> <b class="option">-option</b>". The list of supported options and their meaning can be found in section <span class="sectref"><a href="#section3">OPTIONS</a></span>.</p></dd> <dt><a name="7"><b class="cmd">::nameserv::server::configure</b> <b class="option">-option</b> <i class="arg">value</i>...</a></dt> <dd><p>In this form the command is used to configure one or more of the supported options. At least one option has to be specified, and each option is followed by its new value. The list of supported options and their meaning can be found in |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/oometa/oometa.html.
︙ | ︙ | |||
242 243 244 245 246 247 248 | <dt><a name="11"><b class="cmd">oo::object method meta</b></a></dt> <dd><p>The package injects a new method <b class="cmd">meta</b> into <b class="cmd">oo::object</b>. <b class="cmd">oo::object</b> combines the data for its class (as provided by <b class="cmd">oo::meta::metadata</b>), with a local variable <em>meta</em> to produce a local picture of metadata. This method provides the following additional commands:</p></dd> <dt><a name="12"><b class="cmd">oo::object method meta cget</b> <span class="opt">?<i class="arg">field</i>?</span> <span class="opt">?<i class="arg">...</i>?</span> <i class="arg">field</i></a></dt> <dd><p>Attempts to locate a singlar leaf, and return its value. For single option lookups, this | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | <dt><a name="11"><b class="cmd">oo::object method meta</b></a></dt> <dd><p>The package injects a new method <b class="cmd">meta</b> into <b class="cmd">oo::object</b>. <b class="cmd">oo::object</b> combines the data for its class (as provided by <b class="cmd">oo::meta::metadata</b>), with a local variable <em>meta</em> to produce a local picture of metadata. This method provides the following additional commands:</p></dd> <dt><a name="12"><b class="cmd">oo::object method meta cget</b> <span class="opt">?<i class="arg">field</i>?</span> <span class="opt">?<i class="arg">...</i>?</span> <i class="arg">field</i></a></dt> <dd><p>Attempts to locate a singlar leaf, and return its value. For single option lookups, this is faster than <b class="cmd">my meta getnull</b> <span class="opt">?<i class="arg">field</i>?</span> <span class="opt">?<i class="arg">...</i>?</span> <i class="arg">field</i>, because it performs a search instead directly instead of producing the recursive merge product between the class metadata, the local <em>meta</em> variable, and THEN performing the search.</p></dd> </dl> </div> <div id="section5" class="doctools_section"><h2><a name="section5">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/pop3d/pop3d.html.
︙ | ︙ | |||
273 274 275 276 277 278 279 | <p>Here we describe the interface which has to be provided by the storage callback so that pop3 servers following the interface of this module are able to use it. The <i class="arg">mbox</i> argument is the storage reference as returned by the <b class="method">lookup</b> method of the authentication command, see section <span class="sectref"><a href="#section3">Authentication</a></span>.</p> <dl class="doctools_definitions"> <dt><a name="14"><i class="arg">storageCmd</i> <b class="method">dele</b> <i class="arg">mbox</i> <i class="arg">msgList</i></a></dt> | < | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | <p>Here we describe the interface which has to be provided by the storage callback so that pop3 servers following the interface of this module are able to use it. The <i class="arg">mbox</i> argument is the storage reference as returned by the <b class="method">lookup</b> method of the authentication command, see section <span class="sectref"><a href="#section3">Authentication</a></span>.</p> <dl class="doctools_definitions"> <dt><a name="14"><i class="arg">storageCmd</i> <b class="method">dele</b> <i class="arg">mbox</i> <i class="arg">msgList</i></a></dt> <dd><p>Deletes the messages whose numeric ids are contained in the <i class="arg">msgList</i> from the mailbox specified via <i class="arg">mbox</i>.</p></dd> <dt><a name="15"><i class="arg">storageCmd</i> <b class="method">lock</b> <i class="arg">mbox</i></a></dt> <dd><p>This method locks the specified mailbox for use by a single connection to the server. This is necessary to prevent havoc if several connections to the same mailbox are open. The complementary method is <b class="method">unlock</b>. The command will return true if the lock could be set successfully or false if not.</p></dd> |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/practcl/practcl.html.
︙ | ︙ | |||
94 95 96 97 98 99 100 | </head> <!-- Generated from file 'practcl.man' by tcllib/doctools with format 'html' --> <!-- Copyright &copy; 2016-2018 Sean Woods &lt;[email protected]&gt; --> <!-- practcl.n --> | < < < < < < < < < | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < < > > > > | | | | | | | | | | < < < < < < > | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 | </head> <!-- Generated from file 'practcl.man' by tcllib/doctools with format 'html' --> <!-- Copyright &copy; 2016-2018 Sean Woods &lt;[email protected]&gt; --> <!-- practcl.n --> <body><div class="doctools"> <h1 class="doctools_title">practcl(n) 0.12 practcl "The The Proper Rational API for C to Tool Command Language Module"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>practcl - The Practcl Module</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">Commands</a></li> <li class="doctools_section"><a href="#section3">Classes</a> <ul> <li class="doctools_subsection"><a href="#subsection1">Class practcl::metaclass</a></li> <li class="doctools_subsection"><a href="#subsection2">Class practcl::toolset</a></li> <li class="doctools_subsection"><a href="#subsection3">Class practcl::toolset.gcc</a></li> <li class="doctools_subsection"><a href="#subsection4">Class practcl::toolset.msvc</a></li> <li class="doctools_subsection"><a href="#subsection5">Class practcl::make_obj</a></li> <li class="doctools_subsection"><a href="#subsection6">Class practcl::object</a></li> <li class="doctools_subsection"><a href="#subsection7">Class practcl::dynamic</a></li> <li class="doctools_subsection"><a href="#subsection8">Class practcl::product</a></li> <li class="doctools_subsection"><a href="#subsection9">Class practcl::product.cheader</a></li> <li class="doctools_subsection"><a href="#subsection10">Class practcl::product.csource</a></li> <li class="doctools_subsection"><a href="#subsection11">Class practcl::product.clibrary</a></li> <li class="doctools_subsection"><a href="#subsection12">Class practcl::product.dynamic</a></li> <li class="doctools_subsection"><a href="#subsection13">Class practcl::product.critcl</a></li> <li class="doctools_subsection"><a href="#subsection14">Class practcl::module</a></li> <li class="doctools_subsection"><a href="#subsection15">Class practcl::project</a></li> <li class="doctools_subsection"><a href="#subsection16">Class practcl::library</a></li> <li class="doctools_subsection"><a href="#subsection17">Class practcl::tclkit</a></li> <li class="doctools_subsection"><a href="#subsection18">Class practcl::distribution</a></li> <li class="doctools_subsection"><a href="#subsection19">Class practcl::distribution.snapshot</a></li> <li class="doctools_subsection"><a href="#subsection20">Class practcl::distribution.fossil</a></li> <li class="doctools_subsection"><a href="#subsection21">Class practcl::distribution.git</a></li> <li class="doctools_subsection"><a href="#subsection22">Class practcl::subproject</a></li> <li class="doctools_subsection"><a href="#subsection23">Class practcl::subproject.source</a></li> <li class="doctools_subsection"><a href="#subsection24">Class practcl::subproject.teapot</a></li> <li class="doctools_subsection"><a href="#subsection25">Class practcl::subproject.kettle</a></li> <li class="doctools_subsection"><a href="#subsection26">Class practcl::subproject.critcl</a></li> <li class="doctools_subsection"><a href="#subsection27">Class practcl::subproject.sak</a></li> <li class="doctools_subsection"><a href="#subsection28">Class practcl::subproject.binary</a></li> <li class="doctools_subsection"><a href="#subsection29">Class practcl::subproject.tea</a></li> <li class="doctools_subsection"><a href="#subsection30">Class practcl::subproject.library</a></li> <li class="doctools_subsection"><a href="#subsection31">Class practcl::subproject.external</a></li> <li class="doctools_subsection"><a href="#subsection32">Class practcl::subproject.core</a></li> </ul> </li> <li class="doctools_section"><a href="#section4">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">TclOO 1.0</b></li> <li>package require <b class="pkgname">practcl 0.12</b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1">proc <b class="cmd">Proc</b> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></li> <li><a href="#2">proc <b class="cmd">noop</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#3">proc <b class="cmd">practcl::debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#4">proc <b class="cmd">practcl::doexec</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#5">proc <b class="cmd">practcl::doexec_in</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#6">proc <b class="cmd">practcl::dotclexec</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#7">proc <b class="cmd">practcl::domake</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#8">proc <b class="cmd">practcl::domake.tcl</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#9">proc <b class="cmd">practcl::fossil</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#10">proc <b class="cmd">practcl::fossil_status</b> <i class="arg">dir</i></a></li> <li><a href="#11">proc <b class="cmd">practcl::os</b></a></li> <li><a href="#12">proc <b class="cmd">practcl::mkzip</b> <i class="arg">exename</i> <i class="arg">barekit</i> <i class="arg">vfspath</i></a></li> <li><a href="#13">proc <b class="cmd">practcl::sort_dict</b> <i class="arg">list</i></a></li> <li><a href="#14">proc <b class="cmd">practcl::local_os</b></a></li> <li><a href="#15">proc <b class="cmd">practcl::config.tcl</b> <i class="arg">path</i></a></li> <li><a href="#16">proc <b class="cmd">practcl::read_configuration</b> <i class="arg">path</i></a></li> <li><a href="#17">proc <b class="cmd">practcl::tcllib_require</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#18">proc <b class="cmd">practcl::platform::tcl_core_options</b> <i class="arg">os</i></a></li> <li><a href="#19">proc <b class="cmd">practcl::platform::tk_core_options</b> <i class="arg">os</i></a></li> <li><a href="#20">proc <b class="cmd">practcl::read_rc_file</b> <i class="arg">filename</i> <span class="opt">?<i class="arg">localdat</i> <b class="const"></b>?</span></a></li> <li><a href="#21">proc <b class="cmd">practcl::read_sh_subst</b> <i class="arg">line</i> <i class="arg">info</i></a></li> <li><a href="#22">proc <b class="cmd">practcl::read_sh_file</b> <i class="arg">filename</i> <span class="opt">?<i class="arg">localdat</i> <b class="const"></b>?</span></a></li> <li><a href="#23">proc <b class="cmd">practcl::read_Config.sh</b> <i class="arg">filename</i></a></li> <li><a href="#24">proc <b class="cmd">practcl::read_Makefile</b> <i class="arg">filename</i></a></li> <li><a href="#25">proc <b class="cmd">practcl::cputs</b> <i class="arg">varname</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#26">proc <b class="cmd">practcl::tcl_to_c</b> <i class="arg">body</i></a></li> <li><a href="#27">proc <b class="cmd">practcl::_tagblock</b> <i class="arg">text</i> <span class="opt">?<i class="arg">style</i> <b class="const">tcl</b>?</span> <span class="opt">?<i class="arg">note</i> <b class="const"></b>?</span></a></li> <li><a href="#28">proc <b class="cmd">practcl::de_shell</b> <i class="arg">data</i></a></li> <li><a href="#29">proc <b class="cmd">practcl::cat</b> <i class="arg">fname</i></a></li> <li><a href="#30">proc <b class="cmd">practcl::grep</b> <i class="arg">pattern</i> <span class="opt">?<i class="arg">files</i> <b class="const"></b>?</span></a></li> <li><a href="#31">proc <b class="cmd">practcl::file_lexnormalize</b> <i class="arg">sp</i></a></li> <li><a href="#32">proc <b class="cmd">practcl::file_relative</b> <i class="arg">base</i> <i class="arg">dst</i></a></li> <li><a href="#33">proc <b class="cmd">practcl::log</b> <i class="arg">fname</i> <i class="arg">comment</i></a></li> <li><a href="#34">proc <b class="cmd">practcl::_isdirectory</b> <i class="arg">name</i></a></li> <li><a href="#35">proc <b class="cmd">practcl::_pkgindex_directory</b> <i class="arg">path</i></a></li> <li><a href="#36">proc <b class="cmd">practcl::_pkgindex_path_subdir</b> <i class="arg">path</i></a></li> <li><a href="#37">proc <b class="cmd">practcl::pkgindex_path</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#38">proc <b class="cmd">practcl::installDir</b> <i class="arg">d1</i> <i class="arg">d2</i></a></li> <li><a href="#39">proc <b class="cmd">practcl::copyDir</b> <i class="arg">d1</i> <i class="arg">d2</i> <span class="opt">?<i class="arg">toplevel</i> <b class="const">1</b>?</span></a></li> <li><a href="#40">proc <b class="cmd">practcl::trigger</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#41">proc <b class="cmd">practcl::depends</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#42">proc <b class="cmd">practcl::target</b> <i class="arg">name</i> <i class="arg">info</i> <span class="opt">?<i class="arg">action</i> <b class="const"></b>?</span></a></li> <li><a href="#43">method <b class="cmd">_MorphPatterns</b></a></li> <li><a href="#44">method <b class="cmd">define</b> <i class="arg">submethod</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#45">method <b class="cmd">graft</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#46">method <b class="cmd">initialize</b></a></li> <li><a href="#47">method <b class="cmd">link</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#48">method <b class="cmd">morph</b> <i class="arg">classname</i></a></li> <li><a href="#49">method <b class="cmd">mixin</b> <i class="arg">slot</i> <i class="arg">classname</i></a></li> <li><a href="#50">method <b class="cmd">organ</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#51">method <b class="cmd">script</b> <i class="arg">script</i></a></li> <li><a href="#52">method <b class="cmd">select</b></a></li> <li><a href="#53">method <b class="cmd">source</b> <i class="arg">filename</i></a></li> <li><a href="#54">method <b class="cmd">select</b> <i class="arg">object</i></a></li> <li><a href="#55">method <b class="cmd">config.sh</b></a></li> <li><a href="#56">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#57">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></li> <li><a href="#58">method <b class="cmd">read_configuration</b></a></li> <li><a href="#59">method <b class="cmd">build-cflags</b> <i class="arg">PROJECT</i> <i class="arg">DEFS</i> <i class="arg">namevar</i> <i class="arg">versionvar</i> <i class="arg">defsvar</i></a></li> <li><a href="#60">method <b class="cmd">critcl</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#61">method <b class="cmd">make-autodetect</b></a></li> <li><a href="#62">method <b class="cmd">Autoconf</b></a></li> <li><a href="#63">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#64">method <b class="cmd">ConfigureOpts</b></a></li> <li><a href="#65">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></li> <li><a href="#66">method <b class="cmd">make-autodetect</b></a></li> <li><a href="#67">method <b class="cmd">make-clean</b></a></li> <li><a href="#68">method <b class="cmd">make-compile</b></a></li> <li><a href="#69">method <b class="cmd">make-install</b> <i class="arg">DEST</i></a></li> <li><a href="#70">method <b class="cmd">build-compile-sources</b> <i class="arg">PROJECT</i> <i class="arg">COMPILE</i> <i class="arg">CPPCOMPILE</i> <i class="arg">INCLUDES</i></a></li> <li><a href="#71">method <b class="cmd">build-Makefile</b> <i class="arg">path</i> <i class="arg">PROJECT</i></a></li> <li><a href="#72">method <b class="cmd">build-library</b> <i class="arg">outfile</i> <i class="arg">PROJECT</i></a></li> <li><a href="#73">method <b class="cmd">build-tclsh</b> <i class="arg">outfile</i> <i class="arg">PROJECT</i></a></li> <li><a href="#74">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#75">method <b class="cmd">make-autodetect</b></a></li> <li><a href="#76">method <b class="cmd">make-clean</b></a></li> <li><a href="#77">method <b class="cmd">make-compile</b></a></li> <li><a href="#78">method <b class="cmd">make-install</b> <i class="arg">DEST</i></a></li> <li><a href="#79">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></li> <li><a href="#80">method <b class="cmd">NmakeOpts</b></a></li> <li><a href="#81">method <b class="cmd">constructor</b> <i class="arg">module_object</i> <i class="arg">name</i> <i class="arg">info</i> <span class="opt">?<i class="arg">action_body</i> <b class="const"></b>?</span></a></li> <li><a href="#82">method <b class="cmd">do</b></a></li> <li><a href="#83">method <b class="cmd">check</b></a></li> <li><a href="#84">method <b class="cmd">output</b></a></li> <li><a href="#85">method <b class="cmd">reset</b></a></li> <li><a href="#86">method <b class="cmd">triggers</b></a></li> <li><a href="#87">method <b class="cmd">constructor</b> <i class="arg">parent</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#88">method <b class="cmd">child</b> <i class="arg">method</i></a></li> <li><a href="#89">method <b class="cmd">go</b></a></li> <li><a href="#90">method <b class="cmd">cstructure</b> <i class="arg">name</i> <i class="arg">definition</i> <span class="opt">?<i class="arg">argdat</i> <b class="const"></b>?</span></a></li> <li><a href="#91">method <b class="cmd">include</b> <i class="arg">header</i></a></li> <li><a href="#92">method <b class="cmd">include_dir</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#93">method <b class="cmd">include_directory</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#94">method <b class="cmd">c_header</b> <i class="arg">body</i></a></li> <li><a href="#95">method <b class="cmd">c_code</b> <i class="arg">body</i></a></li> <li><a href="#96">method <b class="cmd">c_function</b> <i class="arg">header</i> <i class="arg">body</i> <span class="opt">?<i class="arg">info</i> <b class="const"></b>?</span></a></li> <li><a href="#97">method <b class="cmd">c_tcloomethod</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></li> <li><a href="#98">method <b class="cmd">cmethod</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></li> <li><a href="#99">method <b class="cmd">c_tclproc_nspace</b> <i class="arg">nspace</i></a></li> <li><a href="#100">method <b class="cmd">c_tclcmd</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></li> <li><a href="#101">method <b class="cmd">c_tclproc_raw</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></li> <li><a href="#102">method <b class="cmd">tcltype</b> <i class="arg">name</i> <i class="arg">argdat</i></a></li> <li><a href="#103">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#104">method <b class="cmd">implement</b> <i class="arg">path</i></a></li> <li><a href="#105">method <b class="cmd">initialize</b></a></li> <li><a href="#106">method <b class="cmd">linktype</b></a></li> <li><a href="#107">method <b class="cmd">generate-cfile-constant</b></a></li> <li><a href="#108">method <b class="cmd">generate-cfile-header</b></a></li> <li><a href="#109">method <b class="cmd">generate-cfile-tclapi</b></a></li> <li><a href="#110">method <b class="cmd">generate-loader-module</b></a></li> <li><a href="#111">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></li> <li><a href="#112">method <b class="cmd">select</b></a></li> <li><a href="#113">method <b class="cmd">select</b> <i class="arg">object</i></a></li> <li><a href="#114">method <b class="cmd">code</b> <i class="arg">section</i> <i class="arg">body</i></a></li> <li><a href="#115">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></li> <li><a href="#116">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#117">method <b class="cmd">generate-debug</b> <span class="opt">?<i class="arg">spaces</i> <b class="const"></b>?</span></a></li> <li><a href="#118">method <b class="cmd">generate-cfile-constant</b></a></li> <li><a href="#119">method <b class="cmd">generate-cfile-public-structure</b></a></li> <li><a href="#120">method <b class="cmd">generate-cfile-header</b></a></li> <li><a href="#121">method <b class="cmd">generate-cfile-global</b></a></li> <li><a href="#122">method <b class="cmd">generate-cfile-private-typedef</b></a></li> <li><a href="#123">method <b class="cmd">generate-cfile-private-structure</b></a></li> <li><a href="#124">method <b class="cmd">generate-cfile-functions</b></a></li> <li><a href="#125">method <b class="cmd">generate-cfile-tclapi</b></a></li> <li><a href="#126">method <b class="cmd">generate-hfile-public-define</b></a></li> <li><a href="#127">method <b class="cmd">generate-hfile-public-macro</b></a></li> <li><a href="#128">method <b class="cmd">generate-hfile-public-typedef</b></a></li> <li><a href="#129">method <b class="cmd">generate-hfile-public-structure</b></a></li> <li><a href="#130">method <b class="cmd">generate-hfile-public-headers</b></a></li> <li><a href="#131">method <b class="cmd">generate-hfile-public-function</b></a></li> <li><a href="#132">method <b class="cmd">generate-hfile-public-includes</b></a></li> <li><a href="#133">method <b class="cmd">generate-hfile-public-verbatim</b></a></li> <li><a href="#134">method <b class="cmd">generate-loader-external</b></a></li> <li><a href="#135">method <b class="cmd">generate-loader-module</b></a></li> <li><a href="#136">method <b class="cmd">generate-stub-function</b></a></li> <li><a href="#137">method <b class="cmd">IncludeAdd</b> <i class="arg">headervar</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#138">method <b class="cmd">generate-tcl-loader</b></a></li> <li><a href="#139">method <b class="cmd">generate-tcl-pre</b></a></li> <li><a href="#140">method <b class="cmd">generate-tcl-post</b></a></li> <li><a href="#141">method <b class="cmd">linktype</b></a></li> <li><a href="#142">method <b class="cmd">Ofile</b> <i class="arg">filename</i></a></li> <li><a href="#143">method <b class="cmd">project-static-packages</b></a></li> <li><a href="#144">method <b class="cmd">toolset-include-directory</b></a></li> <li><a href="#145">method <b class="cmd">target</b> <i class="arg">method</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#146">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#147">method <b class="cmd">generate-loader-module</b></a></li> <li><a href="#148">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#149">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></li> <li><a href="#150">method <b class="cmd">initialize</b></a></li> <li><a href="#151">method <b class="cmd">_MorphPatterns</b></a></li> <li><a href="#152">method <b class="cmd">add</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#153">method <b class="cmd">install-headers</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#154">method <b class="cmd">make</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#155">method <b class="cmd">child</b> <i class="arg">which</i></a></li> <li><a href="#156">method <b class="cmd">generate-c</b></a></li> <li><a href="#157">method <b class="cmd">generate-h</b></a></li> <li><a href="#158">method <b class="cmd">generate-loader</b></a></li> <li><a href="#159">method <b class="cmd">initialize</b></a></li> <li><a href="#160">method <b class="cmd">implement</b> <i class="arg">path</i></a></li> <li><a href="#161">method <b class="cmd">linktype</b></a></li> <li><a href="#162">method <b class="cmd">_MorphPatterns</b></a></li> <li><a href="#163">method <b class="cmd">constructor</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#164">method <b class="cmd">add_object</b> <i class="arg">object</i></a></li> <li><a href="#165">method <b class="cmd">add_project</b> <i class="arg">pkg</i> <i class="arg">info</i> <span class="opt">?<i class="arg">oodefine</i> <b class="const"></b>?</span></a></li> <li><a href="#166">method <b class="cmd">add_tool</b> <i class="arg">pkg</i> <i class="arg">info</i> <span class="opt">?<i class="arg">oodefine</i> <b class="const"></b>?</span></a></li> <li><a href="#167">method <b class="cmd">build-tclcore</b></a></li> <li><a href="#168">method <b class="cmd">child</b> <i class="arg">which</i></a></li> <li><a href="#169">method <b class="cmd">linktype</b></a></li> <li><a href="#170">method <b class="cmd">project</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#171">method <b class="cmd">tclcore</b></a></li> <li><a href="#172">method <b class="cmd">tkcore</b></a></li> <li><a href="#173">method <b class="cmd">tool</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#174">method <b class="cmd">clean</b> <i class="arg">PATH</i></a></li> <li><a href="#175">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#176">method <b class="cmd">go</b></a></li> <li><a href="#177">method <b class="cmd">generate-decls</b> <i class="arg">pkgname</i> <i class="arg">path</i></a></li> <li><a href="#178">method <b class="cmd">implement</b> <i class="arg">path</i></a></li> <li><a href="#179">method <b class="cmd">generate-make</b> <i class="arg">path</i></a></li> <li><a href="#180">method <b class="cmd">linktype</b></a></li> <li><a href="#181">method <b class="cmd">package-ifneeded</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#182">method <b class="cmd">shared_library</b> <span class="opt">?<i class="arg">filename</i> <b class="const"></b>?</span></a></li> <li><a href="#183">method <b class="cmd">static_library</b> <span class="opt">?<i class="arg">filename</i> <b class="const"></b>?</span></a></li> <li><a href="#184">method <b class="cmd">build-tclkit_main</b> <i class="arg">PROJECT</i> <i class="arg">PKG_OBJS</i></a></li> <li><a href="#185">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></li> <li><a href="#186">method <b class="cmd">wrap</b> <i class="arg">PWD</i> <i class="arg">exename</i> <i class="arg">vfspath</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#187">method <b class="cmd">Sandbox</b> <i class="arg">object</i></a></li> <li><a href="#188">method <b class="cmd">select</b> <i class="arg">object</i></a></li> <li><a href="#189">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></li> <li><a href="#190">method <b class="cmd">claim_object</b> <i class="arg">object</i></a></li> <li><a href="#191">method <b class="cmd">scm_info</b></a></li> <li><a href="#192">method <b class="cmd">DistroMixIn</b></a></li> <li><a href="#193">method <b class="cmd">Sandbox</b></a></li> <li><a href="#194">method <b class="cmd">SrcDir</b></a></li> <li><a href="#195">method <b class="cmd">ScmTag</b></a></li> <li><a href="#196">method <b class="cmd">ScmClone</b></a></li> <li><a href="#197">method <b class="cmd">ScmUnpack</b></a></li> <li><a href="#198">method <b class="cmd">ScmUpdate</b></a></li> <li><a href="#199">method <b class="cmd">Unpack</b></a></li> <li><a href="#200">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></li> <li><a href="#201">method <b class="cmd">claim_object</b> <i class="arg">object</i></a></li> <li><a href="#202">method <b class="cmd">ScmUnpack</b></a></li> <li><a href="#203">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></li> <li><a href="#204">method <b class="cmd">claim_object</b> <i class="arg">obj</i></a></li> <li><a href="#205">method <b class="cmd">scm_info</b></a></li> <li><a href="#206">method <b class="cmd">ScmClone</b></a></li> <li><a href="#207">method <b class="cmd">ScmTag</b></a></li> <li><a href="#208">method <b class="cmd">ScmUnpack</b></a></li> <li><a href="#209">method <b class="cmd">ScmUpdate</b></a></li> <li><a href="#210">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></li> <li><a href="#211">method <b class="cmd">claim_object</b> <i class="arg">obj</i></a></li> <li><a href="#212">method <b class="cmd">ScmTag</b></a></li> <li><a href="#213">method <b class="cmd">ScmUnpack</b></a></li> <li><a href="#214">method <b class="cmd">ScmUpdate</b></a></li> <li><a href="#215">method <b class="cmd">_MorphPatterns</b></a></li> <li><a href="#216">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#217">method <b class="cmd">child</b> <i class="arg">which</i></a></li> <li><a href="#218">method <b class="cmd">compile</b></a></li> <li><a href="#219">method <b class="cmd">go</b></a></li> <li><a href="#220">method <b class="cmd">install</b> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#221">method <b class="cmd">linktype</b></a></li> <li><a href="#222">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></li> <li><a href="#223">method <b class="cmd">linker-external</b> <i class="arg">configdict</i></a></li> <li><a href="#224">method <b class="cmd">linker-extra</b> <i class="arg">configdict</i></a></li> <li><a href="#225">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#226">method <b class="cmd">env-exec</b></a></li> <li><a href="#227">method <b class="cmd">env-install</b></a></li> <li><a href="#228">method <b class="cmd">env-load</b></a></li> <li><a href="#229">method <b class="cmd">env-present</b></a></li> <li><a href="#230">method <b class="cmd">sources</b></a></li> <li><a href="#231">method <b class="cmd">update</b></a></li> <li><a href="#232">method <b class="cmd">unpack</b></a></li> <li><a href="#233">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#234">method <b class="cmd">env-present</b></a></li> <li><a href="#235">method <b class="cmd">linktype</b></a></li> <li><a href="#236">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#237">method <b class="cmd">env-install</b></a></li> <li><a href="#238">method <b class="cmd">env-present</b></a></li> <li><a href="#239">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#240">method <b class="cmd">kettle</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#241">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#242">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#243">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#244">method <b class="cmd">env-install</b></a></li> <li><a href="#245">method <b class="cmd">env-present</b></a></li> <li><a href="#246">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#247">method <b class="cmd">install-module</b> <i class="arg">DEST</i> <span class="opt">?<i class="arg">args</i>?</span></a></li> <li><a href="#248">method <b class="cmd">clean</b></a></li> <li><a href="#249">method <b class="cmd">env-install</b></a></li> <li><a href="#250">method <b class="cmd">project-compile-products</b></a></li> <li><a href="#251">method <b class="cmd">ComputeInstall</b></a></li> <li><a href="#252">method <b class="cmd">go</b></a></li> <li><a href="#253">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></li> <li><a href="#254">method <b class="cmd">project-static-packages</b></a></li> <li><a href="#255">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></li> <li><a href="#256">method <b class="cmd">compile</b></a></li> <li><a href="#257">method <b class="cmd">Configure</b></a></li> <li><a href="#258">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#259">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#260">method <b class="cmd">install</b> <i class="arg">DEST</i></a></li> <li><a href="#261">method <b class="cmd">env-bootstrap</b></a></li> <li><a href="#262">method <b class="cmd">env-present</b></a></li> <li><a href="#263">method <b class="cmd">env-install</b></a></li> <li><a href="#264">method <b class="cmd">go</b></a></li> <li><a href="#265">method <b class="cmd">linktype</b></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>The Practcl module is a tool for integrating large modules for C API Tcl code that requires custom Tcl types and TclOO objects.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">Commands</a></h2> <dl class="doctools_definitions"> <dt><a name="1">proc <b class="cmd">Proc</b> <i class="arg">name</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd><p>Generate a proc if no command already exists by that name</p></dd> <dt><a name="2">proc <b class="cmd">noop</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>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</p></dd> <dt><a name="3">proc <b class="cmd">practcl::debug</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="4">proc <b class="cmd">practcl::doexec</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Drop in a static copy of Tcl</p></dd> <dt><a name="5">proc <b class="cmd">practcl::doexec_in</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="6">proc <b class="cmd">practcl::dotclexec</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="7">proc <b class="cmd">practcl::domake</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="8">proc <b class="cmd">practcl::domake.tcl</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="9">proc <b class="cmd">practcl::fossil</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="10">proc <b class="cmd">practcl::fossil_status</b> <i class="arg">dir</i></a></dt> <dd></dd> <dt><a name="11">proc <b class="cmd">practcl::os</b></a></dt> <dd></dd> <dt><a name="12">proc <b class="cmd">practcl::mkzip</b> <i class="arg">exename</i> <i class="arg">barekit</i> <i class="arg">vfspath</i></a></dt> <dd><p>Build a zipfile. On tcl8.6 this invokes the native Zip implementation on older interpreters this invokes zip via exec</p></dd> <dt><a name="13">proc <b class="cmd">practcl::sort_dict</b> <i class="arg">list</i></a></dt> <dd><p>Dictionary sort a key/value list. Needed because pre tcl8.6 does not have <em>lsort -stride 2</em></p></dd> <dt><a name="14">proc <b class="cmd">practcl::local_os</b></a></dt> <dd></dd> <dt><a name="15">proc <b class="cmd">practcl::config.tcl</b> <i class="arg">path</i></a></dt> <dd><p>Detect local platform</p></dd> <dt><a name="16">proc <b class="cmd">practcl::read_configuration</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="17">proc <b class="cmd">practcl::tcllib_require</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Try to load a package, and failing that retrieve tcllib</p></dd> <dt><a name="18">proc <b class="cmd">practcl::platform::tcl_core_options</b> <i class="arg">os</i></a></dt> <dd></dd> <dt><a name="19">proc <b class="cmd">practcl::platform::tk_core_options</b> <i class="arg">os</i></a></dt> <dd></dd> <dt><a name="20">proc <b class="cmd">practcl::read_rc_file</b> <i class="arg">filename</i> <span class="opt">?<i class="arg">localdat</i> <b class="const"></b>?</span></a></dt> <dd><p>Read a stylized key/value list stored in a file</p></dd> <dt><a name="21">proc <b class="cmd">practcl::read_sh_subst</b> <i class="arg">line</i> <i class="arg">info</i></a></dt> <dd></dd> <dt><a name="22">proc <b class="cmd">practcl::read_sh_file</b> <i class="arg">filename</i> <span class="opt">?<i class="arg">localdat</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="23">proc <b class="cmd">practcl::read_Config.sh</b> <i class="arg">filename</i></a></dt> <dd><p>A simpler form of read_sh_file tailored to pulling data from (tcl|tk)Config.sh</p></dd> <dt><a name="24">proc <b class="cmd">practcl::read_Makefile</b> <i class="arg">filename</i></a></dt> <dd><p>A simpler form of read_sh_file tailored to pulling data from a Makefile</p></dd> <dt><a name="25">proc <b class="cmd">practcl::cputs</b> <i class="arg">varname</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>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</p></dd> <dt><a name="26">proc <b class="cmd">practcl::tcl_to_c</b> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="27">proc <b class="cmd">practcl::_tagblock</b> <i class="arg">text</i> <span class="opt">?<i class="arg">style</i> <b class="const">tcl</b>?</span> <span class="opt">?<i class="arg">note</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="28">proc <b class="cmd">practcl::de_shell</b> <i class="arg">data</i></a></dt> <dd></dd> <dt><a name="29">proc <b class="cmd">practcl::cat</b> <i class="arg">fname</i></a></dt> <dd><p>Bits stolen from fileutil</p></dd> <dt><a name="30">proc <b class="cmd">practcl::grep</b> <i class="arg">pattern</i> <span class="opt">?<i class="arg">files</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="31">proc <b class="cmd">practcl::file_lexnormalize</b> <i class="arg">sp</i></a></dt> <dd></dd> <dt><a name="32">proc <b class="cmd">practcl::file_relative</b> <i class="arg">base</i> <i class="arg">dst</i></a></dt> <dd></dd> <dt><a name="33">proc <b class="cmd">practcl::log</b> <i class="arg">fname</i> <i class="arg">comment</i></a></dt> <dd></dd> <dt><a name="34">proc <b class="cmd">practcl::_isdirectory</b> <i class="arg">name</i></a></dt> <dd><p>Installer tools</p></dd> <dt><a name="35">proc <b class="cmd">practcl::_pkgindex_directory</b> <i class="arg">path</i></a></dt> <dd><p>Return true if the pkgindex file contains any statement other than "package ifneeded" and/or if any package ifneeded loads a DLL</p></dd> <dt><a name="36">proc <b class="cmd">practcl::_pkgindex_path_subdir</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="37">proc <b class="cmd">practcl::pkgindex_path</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Index all paths given as though they will end up in the same virtual file system</p></dd> <dt><a name="38">proc <b class="cmd">practcl::installDir</b> <i class="arg">d1</i> <i class="arg">d2</i></a></dt> <dd></dd> <dt><a name="39">proc <b class="cmd">practcl::copyDir</b> <i class="arg">d1</i> <i class="arg">d2</i> <span class="opt">?<i class="arg">toplevel</i> <b class="const">1</b>?</span></a></dt> <dd></dd> <dt><a name="40">proc <b class="cmd">practcl::trigger</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="41">proc <b class="cmd">practcl::depends</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="42">proc <b class="cmd">practcl::target</b> <i class="arg">name</i> <i class="arg">info</i> <span class="opt">?<i class="arg">action</i> <b class="const"></b>?</span></a></dt> <dd></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">Classes</a></h2> <div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Class practcl::metaclass</a></h3> <p><em>ancestors</em>: <b class="class">oo::object</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="43">method <b class="cmd">_MorphPatterns</b></a></dt> <dd></dd> <dt><a name="44">method <b class="cmd">define</b> <i class="arg">submethod</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="45">method <b class="cmd">graft</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="46">method <b class="cmd">initialize</b></a></dt> <dd></dd> <dt><a name="47">method <b class="cmd">link</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="48">method <b class="cmd">morph</b> <i class="arg">classname</i></a></dt> <dd></dd> <dt><a name="49">method <b class="cmd">mixin</b> <i class="arg">slot</i> <i class="arg">classname</i></a></dt> <dd></dd> <dt><a name="50">method <b class="cmd">organ</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="51">method <b class="cmd">script</b> <i class="arg">script</i></a></dt> <dd></dd> <dt><a name="52">method <b class="cmd">select</b></a></dt> <dd></dd> <dt><a name="53">method <b class="cmd">source</b> <i class="arg">filename</i></a></dt> <dd></dd> </dl> </div> <div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">Class practcl::toolset</a></h3> <p>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</p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="54">method <b class="cmd">select</b> <i class="arg">object</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="55">method <b class="cmd">config.sh</b></a></dt> <dd><p>find or fake a key/value list describing this project</p></dd> <dt><a name="56">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd></dd> <dt><a name="57">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></dt> <dd></dd> <dt><a name="58">method <b class="cmd">read_configuration</b></a></dt> <dd></dd> <dt><a name="59">method <b class="cmd">build-cflags</b> <i class="arg">PROJECT</i> <i class="arg">DEFS</i> <i class="arg">namevar</i> <i class="arg">versionvar</i> <i class="arg">defsvar</i></a></dt> <dd><p>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</p></dd> <dt><a name="60">method <b class="cmd">critcl</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="61">method <b class="cmd">make-autodetect</b></a></dt> <dd></dd> </dl> </div> <div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Class practcl::toolset.gcc</a></h3> <p><em>ancestors</em>: <b class="class">practcl::toolset</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="62">method <b class="cmd">Autoconf</b></a></dt> <dd></dd> <dt><a name="63">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd></dd> <dt><a name="64">method <b class="cmd">ConfigureOpts</b></a></dt> <dd></dd> <dt><a name="65">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></dt> <dd><p>Detect what directory contains the Makefile template</p></dd> <dt><a name="66">method <b class="cmd">make-autodetect</b></a></dt> <dd></dd> <dt><a name="67">method <b class="cmd">make-clean</b></a></dt> <dd></dd> <dt><a name="68">method <b class="cmd">make-compile</b></a></dt> <dd></dd> <dt><a name="69">method <b class="cmd">make-install</b> <i class="arg">DEST</i></a></dt> <dd></dd> <dt><a name="70">method <b class="cmd">build-compile-sources</b> <i class="arg">PROJECT</i> <i class="arg">COMPILE</i> <i class="arg">CPPCOMPILE</i> <i class="arg">INCLUDES</i></a></dt> <dd></dd> <dt><a name="71">method <b class="cmd">build-Makefile</b> <i class="arg">path</i> <i class="arg">PROJECT</i></a></dt> <dd></dd> <dt><a name="72">method <b class="cmd">build-library</b> <i class="arg">outfile</i> <i class="arg">PROJECT</i></a></dt> <dd><p>Produce a static or dynamic library</p></dd> <dt><a name="73">method <b class="cmd">build-tclsh</b> <i class="arg">outfile</i> <i class="arg">PROJECT</i></a></dt> <dd><p>Produce a static executable</p></dd> </dl> </div> <div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Class practcl::toolset.msvc</a></h3> <p><em>ancestors</em>: <b class="class">practcl::toolset</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="74">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd><p>MSVC always builds in the source directory</p></dd> <dt><a name="75">method <b class="cmd">make-autodetect</b></a></dt> <dd><p>Do nothing</p></dd> <dt><a name="76">method <b class="cmd">make-clean</b></a></dt> <dd></dd> <dt><a name="77">method <b class="cmd">make-compile</b></a></dt> <dd></dd> <dt><a name="78">method <b class="cmd">make-install</b> <i class="arg">DEST</i></a></dt> <dd></dd> <dt><a name="79">method <b class="cmd">MakeDir</b> <i class="arg">srcdir</i></a></dt> <dd><p>Detect what directory contains the Makefile template</p></dd> <dt><a name="80">method <b class="cmd">NmakeOpts</b></a></dt> <dd></dd> </dl> </div> <div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Class practcl::make_obj</a></h3> <p><em>ancestors</em>: <b class="class">practcl::metaclass</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="81">method <b class="cmd">constructor</b> <i class="arg">module_object</i> <i class="arg">name</i> <i class="arg">info</i> <span class="opt">?<i class="arg">action_body</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="82">method <b class="cmd">do</b></a></dt> <dd></dd> <dt><a name="83">method <b class="cmd">check</b></a></dt> <dd></dd> <dt><a name="84">method <b class="cmd">output</b></a></dt> <dd></dd> <dt><a name="85">method <b class="cmd">reset</b></a></dt> <dd></dd> <dt><a name="86">method <b class="cmd">triggers</b></a></dt> <dd></dd> </dl> </div> <div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Class practcl::object</a></h3> <p><em>ancestors</em>: <b class="class">practcl::metaclass</b></p> <p>A generic Practcl object</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="87">method <b class="cmd">constructor</b> <i class="arg">parent</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="88">method <b class="cmd">child</b> <i class="arg">method</i></a></dt> <dd></dd> <dt><a name="89">method <b class="cmd">go</b></a></dt> <dd></dd> </dl> </div> <div id="subsection7" class="doctools_subsection"><h3><a name="subsection7">Class practcl::dynamic</a></h3> <p>Dynamic blocks do not generate their own .c files, instead the contribute to the amalgamation of the main library file</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="90">method <b class="cmd">cstructure</b> <i class="arg">name</i> <i class="arg">definition</i> <span class="opt">?<i class="arg">argdat</i> <b class="const"></b>?</span></a></dt> <dd><p>Parser functions</p></dd> <dt><a name="91">method <b class="cmd">include</b> <i class="arg">header</i></a></dt> <dd></dd> <dt><a name="92">method <b class="cmd">include_dir</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="93">method <b class="cmd">include_directory</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="94">method <b class="cmd">c_header</b> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="95">method <b class="cmd">c_code</b> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="96">method <b class="cmd">c_function</b> <i class="arg">header</i> <i class="arg">body</i> <span class="opt">?<i class="arg">info</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="97">method <b class="cmd">c_tcloomethod</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="98">method <b class="cmd">cmethod</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></dt> <dd><p>Alias to classic name</p></dd> <dt><a name="99">method <b class="cmd">c_tclproc_nspace</b> <i class="arg">nspace</i></a></dt> <dd></dd> <dt><a name="100">method <b class="cmd">c_tclcmd</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="101">method <b class="cmd">c_tclproc_raw</b> <i class="arg">name</i> <i class="arg">body</i> <span class="opt">?<i class="arg">arginfo</i> <b class="const"></b>?</span></a></dt> <dd><p>Alias to classic name</p></dd> <dt><a name="102">method <b class="cmd">tcltype</b> <i class="arg">name</i> <i class="arg">argdat</i></a></dt> <dd></dd> <dt><a name="103">method <b class="cmd">project-compile-products</b></a></dt> <dd><p>Module interactions</p></dd> <dt><a name="104">method <b class="cmd">implement</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="105">method <b class="cmd">initialize</b></a></dt> <dd><p>Practcl internals</p></dd> <dt><a name="106">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="107">method <b class="cmd">generate-cfile-constant</b></a></dt> <dd></dd> <dt><a name="108">method <b class="cmd">generate-cfile-header</b></a></dt> <dd></dd> <dt><a name="109">method <b class="cmd">generate-cfile-tclapi</b></a></dt> <dd><p>Generate code that provides implements Tcl API calls</p></dd> <dt><a name="110">method <b class="cmd">generate-loader-module</b></a></dt> <dd><p>Generate code that runs when the package/module is initialized into the interpreter</p></dd> <dt><a name="111">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></dt> <dd></dd> <dt><a name="112">method <b class="cmd">select</b></a></dt> <dd><p>Once an object marks itself as some flavor of dynamic, stop trying to morph it into something else</p></dd> </dl> </div> <div id="subsection8" class="doctools_subsection"><h3><a name="subsection8">Class practcl::product</a></h3> <p>A deliverable for the build system</p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="113">method <b class="cmd">select</b> <i class="arg">object</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="114">method <b class="cmd">code</b> <i class="arg">section</i> <i class="arg">body</i></a></dt> <dd></dd> <dt><a name="115">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></dt> <dd></dd> <dt><a name="116">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> <dt><a name="117">method <b class="cmd">generate-debug</b> <span class="opt">?<i class="arg">spaces</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="118">method <b class="cmd">generate-cfile-constant</b></a></dt> <dd></dd> <dt><a name="119">method <b class="cmd">generate-cfile-public-structure</b></a></dt> <dd><p>Populate const static data structures</p></dd> <dt><a name="120">method <b class="cmd">generate-cfile-header</b></a></dt> <dd></dd> <dt><a name="121">method <b class="cmd">generate-cfile-global</b></a></dt> <dd></dd> <dt><a name="122">method <b class="cmd">generate-cfile-private-typedef</b></a></dt> <dd></dd> <dt><a name="123">method <b class="cmd">generate-cfile-private-structure</b></a></dt> <dd></dd> <dt><a name="124">method <b class="cmd">generate-cfile-functions</b></a></dt> <dd><p>Generate code that provides subroutines called by Tcl API methods</p></dd> <dt><a name="125">method <b class="cmd">generate-cfile-tclapi</b></a></dt> <dd><p>Generate code that provides implements Tcl API calls</p></dd> <dt><a name="126">method <b class="cmd">generate-hfile-public-define</b></a></dt> <dd></dd> <dt><a name="127">method <b class="cmd">generate-hfile-public-macro</b></a></dt> <dd></dd> <dt><a name="128">method <b class="cmd">generate-hfile-public-typedef</b></a></dt> <dd></dd> <dt><a name="129">method <b class="cmd">generate-hfile-public-structure</b></a></dt> <dd></dd> <dt><a name="130">method <b class="cmd">generate-hfile-public-headers</b></a></dt> <dd></dd> <dt><a name="131">method <b class="cmd">generate-hfile-public-function</b></a></dt> <dd></dd> <dt><a name="132">method <b class="cmd">generate-hfile-public-includes</b></a></dt> <dd></dd> <dt><a name="133">method <b class="cmd">generate-hfile-public-verbatim</b></a></dt> <dd></dd> <dt><a name="134">method <b class="cmd">generate-loader-external</b></a></dt> <dd></dd> <dt><a name="135">method <b class="cmd">generate-loader-module</b></a></dt> <dd></dd> <dt><a name="136">method <b class="cmd">generate-stub-function</b></a></dt> <dd></dd> <dt><a name="137">method <b class="cmd">IncludeAdd</b> <i class="arg">headervar</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="138">method <b class="cmd">generate-tcl-loader</b></a></dt> <dd></dd> <dt><a name="139">method <b class="cmd">generate-tcl-pre</b></a></dt> <dd><p>This methods generates any Tcl script file which is required to pre-initialize the C library</p></dd> <dt><a name="140">method <b class="cmd">generate-tcl-post</b></a></dt> <dd></dd> <dt><a name="141">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="142">method <b class="cmd">Ofile</b> <i class="arg">filename</i></a></dt> <dd></dd> <dt><a name="143">method <b class="cmd">project-static-packages</b></a></dt> <dd><p>Methods called by the master project</p></dd> <dt><a name="144">method <b class="cmd">toolset-include-directory</b></a></dt> <dd><p>Methods called by the toolset</p></dd> <dt><a name="145">method <b class="cmd">target</b> <i class="arg">method</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection9" class="doctools_subsection"><h3><a name="subsection9">Class practcl::product.cheader</a></h3> <p><em>ancestors</em>: <b class="class">practcl::product</b></p> <p>Flesh out several trivial varieties of product</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="146">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> <dt><a name="147">method <b class="cmd">generate-loader-module</b></a></dt> <dd></dd> </dl> </div> <div id="subsection10" class="doctools_subsection"><h3><a name="subsection10">Class practcl::product.csource</a></h3> <p><em>ancestors</em>: <b class="class">practcl::product</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="148">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> </dl> </div> <div id="subsection11" class="doctools_subsection"><h3><a name="subsection11">Class practcl::product.clibrary</a></h3> <p><em>ancestors</em>: <b class="class">practcl::product</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="149">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></dt> <dd></dd> </dl> </div> <div id="subsection12" class="doctools_subsection"><h3><a name="subsection12">Class practcl::product.dynamic</a></h3> <p><em>ancestors</em>: <b class="class">practcl::dynamic</b> <b class="class">practcl::product</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="150">method <b class="cmd">initialize</b></a></dt> <dd></dd> </dl> </div> <div id="subsection13" class="doctools_subsection"><h3><a name="subsection13">Class practcl::product.critcl</a></h3> <p><em>ancestors</em>: <b class="class">practcl::dynamic</b> <b class="class">practcl::product</b></p> </div> <div id="subsection14" class="doctools_subsection"><h3><a name="subsection14">Class practcl::module</a></h3> <p><em>ancestors</em>: <b class="class">practcl::object</b> <b class="class">practcl::product.dynamic</b></p> <p>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</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="151">method <b class="cmd">_MorphPatterns</b></a></dt> <dd></dd> <dt><a name="152">method <b class="cmd">add</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="153">method <b class="cmd">install-headers</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="154">method <b class="cmd">make</b> <i class="arg">command</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Target handling</p></dd> <dt><a name="155">method <b class="cmd">child</b> <i class="arg">which</i></a></dt> <dd></dd> <dt><a name="156">method <b class="cmd">generate-c</b></a></dt> <dd><p>This methods generates the contents of an amalgamated .c file which implements the loader for a batch of tools</p></dd> <dt><a name="157">method <b class="cmd">generate-h</b></a></dt> <dd><p>This methods generates the contents of an amalgamated .h file which describes the public API of this module</p></dd> <dt><a name="158">method <b class="cmd">generate-loader</b></a></dt> <dd></dd> <dt><a name="159">method <b class="cmd">initialize</b></a></dt> <dd></dd> <dt><a name="160">method <b class="cmd">implement</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="161">method <b class="cmd">linktype</b></a></dt> <dd></dd> </dl> </div> <div id="subsection15" class="doctools_subsection"><h3><a name="subsection15">Class practcl::project</a></h3> <p><em>ancestors</em>: <b class="class">practcl::module</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="162">method <b class="cmd">_MorphPatterns</b></a></dt> <dd></dd> <dt><a name="163">method <b class="cmd">constructor</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="164">method <b class="cmd">add_object</b> <i class="arg">object</i></a></dt> <dd></dd> <dt><a name="165">method <b class="cmd">add_project</b> <i class="arg">pkg</i> <i class="arg">info</i> <span class="opt">?<i class="arg">oodefine</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="166">method <b class="cmd">add_tool</b> <i class="arg">pkg</i> <i class="arg">info</i> <span class="opt">?<i class="arg">oodefine</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="167">method <b class="cmd">build-tclcore</b></a></dt> <dd></dd> <dt><a name="168">method <b class="cmd">child</b> <i class="arg">which</i></a></dt> <dd></dd> <dt><a name="169">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="170">method <b class="cmd">project</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Exercise the methods of a sub-object</p></dd> <dt><a name="171">method <b class="cmd">tclcore</b></a></dt> <dd></dd> <dt><a name="172">method <b class="cmd">tkcore</b></a></dt> <dd></dd> <dt><a name="173">method <b class="cmd">tool</b> <i class="arg">pkg</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection16" class="doctools_subsection"><h3><a name="subsection16">Class practcl::library</a></h3> <p><em>ancestors</em>: <b class="class">practcl::project</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="174">method <b class="cmd">clean</b> <i class="arg">PATH</i></a></dt> <dd></dd> <dt><a name="175">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> <dt><a name="176">method <b class="cmd">go</b></a></dt> <dd></dd> <dt><a name="177">method <b class="cmd">generate-decls</b> <i class="arg">pkgname</i> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="178">method <b class="cmd">implement</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="179">method <b class="cmd">generate-make</b> <i class="arg">path</i></a></dt> <dd><p>Backward compadible call</p></dd> <dt><a name="180">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="181">method <b class="cmd">package-ifneeded</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Create a "package ifneeded" Args are a list of aliases for which this package will answer to</p></dd> <dt><a name="182">method <b class="cmd">shared_library</b> <span class="opt">?<i class="arg">filename</i> <b class="const"></b>?</span></a></dt> <dd></dd> <dt><a name="183">method <b class="cmd">static_library</b> <span class="opt">?<i class="arg">filename</i> <b class="const"></b>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection17" class="doctools_subsection"><h3><a name="subsection17">Class practcl::tclkit</a></h3> <p><em>ancestors</em>: <b class="class">practcl::library</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="184">method <b class="cmd">build-tclkit_main</b> <i class="arg">PROJECT</i> <i class="arg">PKG_OBJS</i></a></dt> <dd></dd> <dt><a name="185">method <b class="cmd">Collate_Source</b> <i class="arg">CWD</i></a></dt> <dd></dd> <dt><a name="186">method <b class="cmd">wrap</b> <i class="arg">PWD</i> <i class="arg">exename</i> <i class="arg">vfspath</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Wrap an executable</p></dd> </dl> </div> <div id="subsection18" class="doctools_subsection"><h3><a name="subsection18">Class practcl::distribution</a></h3> <p>Standalone class to manage code distribution This class is intended to be mixed into another class (Thus the lack of ancestors)</p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="187">method <b class="cmd">Sandbox</b> <i class="arg">object</i></a></dt> <dd></dd> <dt><a name="188">method <b class="cmd">select</b> <i class="arg">object</i></a></dt> <dd></dd> <dt><a name="189">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="190">method <b class="cmd">claim_object</b> <i class="arg">object</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="191">method <b class="cmd">scm_info</b></a></dt> <dd></dd> <dt><a name="192">method <b class="cmd">DistroMixIn</b></a></dt> <dd></dd> <dt><a name="193">method <b class="cmd">Sandbox</b></a></dt> <dd></dd> <dt><a name="194">method <b class="cmd">SrcDir</b></a></dt> <dd></dd> <dt><a name="195">method <b class="cmd">ScmTag</b></a></dt> <dd></dd> <dt><a name="196">method <b class="cmd">ScmClone</b></a></dt> <dd></dd> <dt><a name="197">method <b class="cmd">ScmUnpack</b></a></dt> <dd></dd> <dt><a name="198">method <b class="cmd">ScmUpdate</b></a></dt> <dd></dd> <dt><a name="199">method <b class="cmd">Unpack</b></a></dt> <dd></dd> </dl> </div> <div id="subsection19" class="doctools_subsection"><h3><a name="subsection19">Class practcl::distribution.snapshot</a></h3> <p><em>ancestors</em>: <b class="class">practcl::distribution</b></p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="200">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="201">method <b class="cmd">claim_object</b> <i class="arg">object</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="202">method <b class="cmd">ScmUnpack</b></a></dt> <dd></dd> </dl> </div> <div id="subsection20" class="doctools_subsection"><h3><a name="subsection20">Class practcl::distribution.fossil</a></h3> <p><em>ancestors</em>: <b class="class">practcl::distribution</b></p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="203">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></dt> <dd><p>Check for markers in the source root</p></dd> <dt><a name="204">method <b class="cmd">claim_object</b> <i class="arg">obj</i></a></dt> <dd><p>Check for markers in the metadata</p></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="205">method <b class="cmd">scm_info</b></a></dt> <dd></dd> <dt><a name="206">method <b class="cmd">ScmClone</b></a></dt> <dd><p>Clone the source</p></dd> <dt><a name="207">method <b class="cmd">ScmTag</b></a></dt> <dd></dd> <dt><a name="208">method <b class="cmd">ScmUnpack</b></a></dt> <dd></dd> <dt><a name="209">method <b class="cmd">ScmUpdate</b></a></dt> <dd></dd> </dl> </div> <div id="subsection21" class="doctools_subsection"><h3><a name="subsection21">Class practcl::distribution.git</a></h3> <p><em>ancestors</em>: <b class="class">practcl::distribution</b></p> <p><b class="class">Class Methods</b></p> <dl class="doctools_definitions"> <dt><a name="210">method <b class="cmd">claim_path</b> <i class="arg">path</i></a></dt> <dd></dd> <dt><a name="211">method <b class="cmd">claim_object</b> <i class="arg">obj</i></a></dt> <dd></dd> </dl> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="212">method <b class="cmd">ScmTag</b></a></dt> <dd></dd> <dt><a name="213">method <b class="cmd">ScmUnpack</b></a></dt> <dd></dd> <dt><a name="214">method <b class="cmd">ScmUpdate</b></a></dt> <dd></dd> </dl> </div> <div id="subsection22" class="doctools_subsection"><h3><a name="subsection22">Class practcl::subproject</a></h3> <p><em>ancestors</em>: <b class="class">practcl::module</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="215">method <b class="cmd">_MorphPatterns</b></a></dt> <dd></dd> <dt><a name="216">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd></dd> <dt><a name="217">method <b class="cmd">child</b> <i class="arg">which</i></a></dt> <dd></dd> <dt><a name="218">method <b class="cmd">compile</b></a></dt> <dd></dd> <dt><a name="219">method <b class="cmd">go</b></a></dt> <dd></dd> <dt><a name="220">method <b class="cmd">install</b> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd><p>Install project into the local build system</p></dd> <dt><a name="221">method <b class="cmd">linktype</b></a></dt> <dd></dd> <dt><a name="222">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></dt> <dd></dd> <dt><a name="223">method <b class="cmd">linker-external</b> <i class="arg">configdict</i></a></dt> <dd></dd> <dt><a name="224">method <b class="cmd">linker-extra</b> <i class="arg">configdict</i></a></dt> <dd></dd> <dt><a name="225">method <b class="cmd">env-bootstrap</b></a></dt> <dd><p>Methods for packages/tools that can be downloaded possibly built and used internally by this Practcl process Load the facility into the interpreter</p></dd> <dt><a name="226">method <b class="cmd">env-exec</b></a></dt> <dd><p>Return a file path that exec can call</p></dd> <dt><a name="227">method <b class="cmd">env-install</b></a></dt> <dd><p>Install the tool into the local environment</p></dd> <dt><a name="228">method <b class="cmd">env-load</b></a></dt> <dd><p>Do whatever is necessary to get the tool into the local environment</p></dd> <dt><a name="229">method <b class="cmd">env-present</b></a></dt> <dd><p>Check if tool is available for load/already loaded</p></dd> <dt><a name="230">method <b class="cmd">sources</b></a></dt> <dd></dd> <dt><a name="231">method <b class="cmd">update</b></a></dt> <dd></dd> <dt><a name="232">method <b class="cmd">unpack</b></a></dt> <dd></dd> </dl> </div> <div id="subsection23" class="doctools_subsection"><h3><a name="subsection23">Class practcl::subproject.source</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b> <b class="class">practcl::library</b></p> <p>A project which the kit compiles and integrates the source for itself</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="233">method <b class="cmd">env-bootstrap</b></a></dt> <dd></dd> <dt><a name="234">method <b class="cmd">env-present</b></a></dt> <dd></dd> <dt><a name="235">method <b class="cmd">linktype</b></a></dt> <dd></dd> </dl> </div> <div id="subsection24" class="doctools_subsection"><h3><a name="subsection24">Class practcl::subproject.teapot</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p>a copy from the teapot</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="236">method <b class="cmd">env-bootstrap</b></a></dt> <dd></dd> <dt><a name="237">method <b class="cmd">env-install</b></a></dt> <dd></dd> <dt><a name="238">method <b class="cmd">env-present</b></a></dt> <dd></dd> <dt><a name="239">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection25" class="doctools_subsection"><h3><a name="subsection25">Class practcl::subproject.kettle</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="240">method <b class="cmd">kettle</b> <i class="arg">path</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> <dt><a name="241">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection26" class="doctools_subsection"><h3><a name="subsection26">Class practcl::subproject.critcl</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="242">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection27" class="doctools_subsection"><h3><a name="subsection27">Class practcl::subproject.sak</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="243">method <b class="cmd">env-bootstrap</b></a></dt> <dd></dd> <dt><a name="244">method <b class="cmd">env-install</b></a></dt> <dd></dd> <dt><a name="245">method <b class="cmd">env-present</b></a></dt> <dd></dd> <dt><a name="246">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> <dt><a name="247">method <b class="cmd">install-module</b> <i class="arg">DEST</i> <span class="opt">?<i class="arg">args</i>?</span></a></dt> <dd></dd> </dl> </div> <div id="subsection28" class="doctools_subsection"><h3><a name="subsection28">Class practcl::subproject.binary</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject</b></p> <p>A binary package</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="248">method <b class="cmd">clean</b></a></dt> <dd></dd> <dt><a name="249">method <b class="cmd">env-install</b></a></dt> <dd></dd> <dt><a name="250">method <b class="cmd">project-compile-products</b></a></dt> <dd></dd> <dt><a name="251">method <b class="cmd">ComputeInstall</b></a></dt> <dd></dd> <dt><a name="252">method <b class="cmd">go</b></a></dt> <dd></dd> <dt><a name="253">method <b class="cmd">linker-products</b> <i class="arg">configdict</i></a></dt> <dd></dd> <dt><a name="254">method <b class="cmd">project-static-packages</b></a></dt> <dd></dd> <dt><a name="255">method <b class="cmd">BuildDir</b> <i class="arg">PWD</i></a></dt> <dd></dd> <dt><a name="256">method <b class="cmd">compile</b></a></dt> <dd></dd> <dt><a name="257">method <b class="cmd">Configure</b></a></dt> <dd></dd> <dt><a name="258">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection29" class="doctools_subsection"><h3><a name="subsection29">Class practcl::subproject.tea</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject.binary</b></p> </div> <div id="subsection30" class="doctools_subsection"><h3><a name="subsection30">Class practcl::subproject.library</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject.binary</b> <b class="class">practcl::library</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="259">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection31" class="doctools_subsection"><h3><a name="subsection31">Class practcl::subproject.external</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject.binary</b></p> <p>An external library</p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="260">method <b class="cmd">install</b> <i class="arg">DEST</i></a></dt> <dd></dd> </dl> </div> <div id="subsection32" class="doctools_subsection"><h3><a name="subsection32">Class practcl::subproject.core</a></h3> <p><em>ancestors</em>: <b class="class">practcl::subproject.binary</b></p> <p><b class="class">Methods</b></p> <dl class="doctools_definitions"> <dt><a name="261">method <b class="cmd">env-bootstrap</b></a></dt> <dd></dd> <dt><a name="262">method <b class="cmd">env-present</b></a></dt> <dd></dd> <dt><a name="263">method <b class="cmd">env-install</b></a></dt> <dd></dd> <dt><a name="264">method <b class="cmd">go</b></a></dt> <dd></dd> <dt><a name="265">method <b class="cmd">linktype</b></a></dt> <dd></dd> </dl> </div> </div> <div id="section4" class="doctools_section"><h2><a name="section4">Bugs, Ideas, Feedback</a></h2> <p>This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category <em>practcl</em> of the <a href="http://core.tcl.tk/tcllib/reportlist">Tcllib Trackers</a>. Please also report any ideas for enhancements you may have for either package and/or documentation.</p> <p>When proposing code changes, please provide <em>unified diffs</em>, i.e the output of <b class="const">diff -u</b>.</p> <p>Note further that <em>attachments</em> are strongly preferred over inlined patches. Attachments can be made by going to the <b class="const">Edit</b> form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p>practcl</p> </div> <div id="category" class="doctools_section"><h2><a name="category">Category</a></h2> <p>TclOO</p> </div> <div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2> <p>Copyright © 2016-2018 Sean Woods <[email protected]></p> </div> </div></body></html> |
Changes to idoc/www/tcllib/files/modules/pt/pt_peg_op.html.
︙ | ︙ | |||
104 105 106 107 108 109 110 | | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> | | | | 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 | | <a href="../../../toc.html">Table Of Contents</a> | <a href="../../../../index.html">Keyword Index</a> | <a href="../../../../toc0.html">Categories</a> | <a href="../../../../toc1.html">Modules</a> | <a href="../../../../toc2.html">Applications</a> ] <hr> <div class="doctools"> <h1 class="doctools_title">pt_peg_op(i) 1.0.2 tcllib "Parser Tools"</h1> <div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> <p>pt_peg_op - Parser Tools PE Grammar Utility Operations</p> </div> <div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> <ul class="doctools_toc"> <li class="doctools_section"><a href="#toc">Table Of Contents</a></li> <li class="doctools_section"><a href="#synopsis">Synopsis</a></li> <li class="doctools_section"><a href="#section1">Description</a></li> <li class="doctools_section"><a href="#section2">API</a></li> <li class="doctools_section"><a href="#section3">Bugs, Ideas, Feedback</a></li> <li class="doctools_section"><a href="#keywords">Keywords</a></li> <li class="doctools_section"><a href="#category">Category</a></li> <li class="doctools_section"><a href="#copyright">Copyright</a></li> </ul> </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">Tcl 8.5</b></li> <li>package require <b class="pkgname">pt::peg::op <span class="opt">?1.0.2?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><b class="cmd">::peg::peg::op</b> <b class="method">called</b> <i class="arg">container</i></a></li> <li><a href="#2"><b class="cmd">::peg::peg::op</b> <b class="method">dechain</b> <i class="arg">container</i></a></li> <li><a href="#3"><b class="cmd">::peg::peg::op</b> <b class="method">drop unreachable</b> <i class="arg">container</i></a></li> <li><a href="#4"><b class="cmd">::peg::peg::op</b> <b class="method">drop unrealizable</b> <i class="arg">container</i></a></li> <li><a href="#5"><b class="cmd">::peg::peg::op</b> <b class="method">flatten</b> <i class="arg">container</i></a></li> |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/smtpd/smtpd.html.
︙ | ︙ | |||
296 297 298 299 300 301 302 | <p>The content of any error message will not be passed back to the client.</p></dd> <dt><b class="cmd">validate_recipient</b> callback</dt> <dd><p>The validate_recipient callback is similar to the validate_sender callback and permits you to verify a local mailbox and accept mail for a local user address during RCPT command handling. To reject mail, throw an error as above. The error message is ignored.</p></dd> <dt><b class="cmd">deliverMIME</b> callback</dt> | < | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | <p>The content of any error message will not be passed back to the client.</p></dd> <dt><b class="cmd">validate_recipient</b> callback</dt> <dd><p>The validate_recipient callback is similar to the validate_sender callback and permits you to verify a local mailbox and accept mail for a local user address during RCPT command handling. To reject mail, throw an error as above. The error message is ignored.</p></dd> <dt><b class="cmd">deliverMIME</b> callback</dt> <dd><p>The deliverMIME callback is called once a mail message has been successfully passed to the server. A mime token is constructed from the sender, recipients and data and the users procedure it called with this single argument. When the call returns, the mime token is cleaned up so if the user wishes to preserve the data she must make a copy.</p> <pre class="doctools_example"> proc deliverMIME {token} { set sender [lindex [mime::getheader $token From] 0] |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/stooop/switched.html.
︙ | ︙ | |||
312 313 314 315 316 317 318 | listed in the <b class="method">options</b> procedure) but obviously does not check the validity of the value passed to the <b class="method">set-<b class="option">option</b></b> procedure, which should throw an error (for example by using the Tcl error command) if the value is invalid.</p> <p>The switched layer also keeps track of the options current values, so that a <b class="method">set-<b class="option">option</b></b> procedure is called only when the corresponding option value passed as parameter is | | | | | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | listed in the <b class="method">options</b> procedure) but obviously does not check the validity of the value passed to the <b class="method">set-<b class="option">option</b></b> procedure, which should throw an error (for example by using the Tcl error command) if the value is invalid.</p> <p>The switched layer also keeps track of the options current values, so that a <b class="method">set-<b class="option">option</b></b> procedure is called only when the corresponding option value passed as parameter is different from the current value (see <b class="variable">-option</b> data members description).</p></dd> <dt><b class="variable">-option</b></dt> <dd><p>The <b class="variable">-option</b> data member is an options current value. There is one for each option listed in the options procedure. It is a read-only value which the switched layer checks against when an option is changed. It is rarely used at the layer derived from switched, except in the few cases, such as in the following example:</p> <pre class="doctools_example"> ... |
︙ | ︙ | |||
339 340 341 342 343 344 345 | puts "manufacturer: $switched::($this,-manufacturer)" ... } </pre> <p>In this case, the manufacturer's name is stored at the switched layer level (this is why the set-manufacturer procedure has nothing to do) and later retrieved in the printData procedure.</p></dd> | | | | | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | puts "manufacturer: $switched::($this,-manufacturer)" ... } </pre> <p>In this case, the manufacturer's name is stored at the switched layer level (this is why the set-manufacturer procedure has nothing to do) and later retrieved in the printData procedure.</p></dd> <dt><b class="variable">complete</b></dt> <dd><p>The <b class="variable">complete</b> data member (not to be confused with the <b class="method">complete</b> procedure) is a boolean. Its initial value is <b class="const">false</b> and it is set to <b class="const">true</b> at the very end of the switched <b class="method">complete</b> procedure. It becomes useful when some options should be set at construction time only and not dynamically, as the following example shows:</p> <pre class="doctools_example"> proc car::set-width {this value} { if {$switched::($this,complete)} { |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/tepam/tepam_doc_gen.html.
︙ | ︙ | |||
324 325 326 327 328 329 330 | <dd><p>Generates the part of the command line or the synopsis that is specific to an argument. The generated string has to indicate if an argument is optional, named and if it is a flag.</p> <p>The following parameters are provided to this procedure:</p> <dl class="doctools_definitions"> <dt><i class="arg">Name</i></dt> <dd><p>Name of the argument</p></dd> <dt><i class="arg">IsOptional</i></dt> | | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | <dd><p>Generates the part of the command line or the synopsis that is specific to an argument. The generated string has to indicate if an argument is optional, named and if it is a flag.</p> <p>The following parameters are provided to this procedure:</p> <dl class="doctools_definitions"> <dt><i class="arg">Name</i></dt> <dd><p>Name of the argument</p></dd> <dt><i class="arg">IsOptional</i></dt> <dd><p>If true (=<b class="const">1</b>) the argument is optional which should be indicated by the generated string (for example by putting the argument into brackets {[]} or into question marks '?'):</p> <pre class="doctools_example">gen(TXT,ArgumentString) mtype 1 0 string -> <em>"[mtype]"</em></pre> </dd> <dt><i class="arg">IsNamed</i></dt> <dd><p>If true (=<b class="const">1</b>) an argument is a named argument (option). The generated string should in this case contain the argument/option name, followed by the argument itself:</p> <pre class="doctools_example">gen(TXT,ArgumentString) mtype 0 1 string -> <em>"-mtype <mtype>"</em></pre> <p>Named arguments can also be optional:</p> <pre class="doctools_example">gen(TXT,ArgumentString) mtype 1 1 string -> <em>"[-mtype <mtype>]"</em></pre> |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/tepam/tepam_procedure.html.
︙ | ︙ | |||
715 716 717 718 719 720 721 | <p>Named arguments can be defined multiple times. If the named argument has the <em>-multiply</em> attribute, all argument values will be collected in a list. Otherwise, only the last provided attribute value will be retained:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 -n1 M1 U1 U2</b> <em>-> n1:'M1', n2:'N2', u1:'U1', u2:'U2'</em></pre> <p>The name of the first unnamed argument has therefore not to start with the '-' character. The unnamed argument is otherwise considered as name of another named argument. This is especially important if the first unnamed argument is given by a variable that can contain any character strings:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 "->" "<-"</b> <em>-> my_proc: Argument '->' not known</em> set U1 "->" | | | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 | <p>Named arguments can be defined multiple times. If the named argument has the <em>-multiply</em> attribute, all argument values will be collected in a list. Otherwise, only the last provided attribute value will be retained:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 -n1 M1 U1 U2</b> <em>-> n1:'M1', n2:'N2', u1:'U1', u2:'U2'</em></pre> <p>The name of the first unnamed argument has therefore not to start with the '-' character. The unnamed argument is otherwise considered as name of another named argument. This is especially important if the first unnamed argument is given by a variable that can contain any character strings:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 "->" "<-"</b> <em>-> my_proc: Argument '->' not known</em> set U1 "->" my_proc <b class="cmd">-n1 N1 -n2 N2 $U1 U2</b> my_proc: Argument '->' not known</pre> <p>The '--' flag allows separating unambiguously the unnamed arguments from the named arguments. All data after the '--' flag will be considered as unnamed argument:</p> <pre class="doctools_example">my_proc <b class="cmd">-n1 N1 -n2 N2 -- "->" "<-"</b> <em>-> n1:'N1', n2:'N2', u1:'->', u2:'<-'</em> set U1 "->" my_proc <b class="cmd">-n1 N1 -n2 N2 -- $U1 U2</b> <em>-> n1:'N1', n2:'N2', u1:'->', u2:'<-'</em></pre> |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/textutil/adjust.html.
︙ | ︙ | |||
206 207 208 209 210 211 212 | there are no space chars at the end of this line, and there may be some space chars at the beginning, despite of the <b class="option">-full</b> option.</p></dd> </dl></dd> <dt><b class="option">-length</b> <i class="arg">integer</i></dt> <dd><p>Set the length of the <em>logical</em> line in the string to <i class="arg">integer</i>. <i class="arg">integer</i> must be a positive integer value. Defaults to <b class="const">72</b>.</p></dd> | | < | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | there are no space chars at the end of this line, and there may be some space chars at the beginning, despite of the <b class="option">-full</b> option.</p></dd> </dl></dd> <dt><b class="option">-length</b> <i class="arg">integer</i></dt> <dd><p>Set the length of the <em>logical</em> line in the string to <i class="arg">integer</i>. <i class="arg">integer</i> must be a positive integer value. Defaults to <b class="const">72</b>.</p></dd> <dt><b class="option">-strictlength</b> <i class="arg">boolean</i></dt> <dd><p>If set to <b class="const">false</b> (default), a line can exceed the specified <b class="option">-length</b> if a single word is longer than <b class="option">-length</b>. If set to <b class="const">true</b>, words that are longer than <b class="option">-length</b> are split so that no line exceeds the specified <b class="option">-length</b>.</p></dd> </dl></dd> <dt><a name="2"><b class="cmd">::textutil::adjust::readPatterns</b> <i class="arg">filename</i></a></dt> <dd><p>Loads the internal storage for hyphenation patterns with the contents of the file <i class="arg">filename</i>. This has to be done prior to calling |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/tool/tool_dict_ensemble.html.
︙ | ︙ | |||
126 127 128 129 130 131 132 | </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">tool <span class="opt">?0.4.2?</span></b></li> </ul> <ul class="doctools_syntax"> | | | < | | 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 | </div> <div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> <div class="doctools_synopsis"> <ul class="doctools_requirements"> <li>package require <b class="pkgname">tool <span class="opt">?0.4.2?</span></b></li> </ul> <ul class="doctools_syntax"> <li><a href="#1"><em>object</em> <i class="arg">ensemble</i> <b class="cmd">add</b> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">value ...</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>The <b class="cmd">dict_ensemble</b> command is a keyword added by <b class="package"><a href="tool.html">tool</a></b>. It defines a public variable (stored as a dict), and an access function to manipulated and access the values stored in that dict.</p> <dl class="doctools_definitions"> <dt><a name="1"><em>object</em> <i class="arg">ensemble</i> <b class="cmd">add</b> <i class="arg">field</i> <i class="arg">value</i> <i class="arg">value ...</i></a></dt> <dd><p>Adds elements to a list maintained with the <i class="arg">field</i> leaf of the dict maintained my this ensemble. Declares a variable <i class="arg">name</i> which will be initialized as an array, populated with <i class="arg">contents</i> for objects of this class, as well as any objects for classes which are descendents of this class.</p></dd> </dl> </div> <div id="section2" class="doctools_section"><h2><a name="section2">AUTHORS</a></h2> <p>Sean Woods</p> |
︙ | ︙ |
Changes to idoc/www/tcllib/files/modules/websocket/websocket.html.
︙ | ︙ | |||
290 291 292 293 294 295 296 | <dt><a name="3"><b class="cmd">::websocket::server</b> <i class="arg">sock</i></a></dt> <dd><p>This command registers the (accept) socket <i class="arg">sock</i> as the identifier fo an HTTP server that is capable of doing WebSockets. Paths onto which this server will listen for incoming connections should be declared using <b class="cmd">::websocket::live</b>.</p></dd> <dt><a name="4"><b class="cmd">::websocket::live</b> <i class="arg">sock</i> <i class="arg">path</i> <i class="arg">cb</i> <span class="opt">?<i class="arg">proto</i>?</span></a></dt> <dd><p>This procedure registers callbacks that will be performed on a | | | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | <dt><a name="3"><b class="cmd">::websocket::server</b> <i class="arg">sock</i></a></dt> <dd><p>This command registers the (accept) socket <i class="arg">sock</i> as the identifier fo an HTTP server that is capable of doing WebSockets. Paths onto which this server will listen for incoming connections should be declared using <b class="cmd">::websocket::live</b>.</p></dd> <dt><a name="4"><b class="cmd">::websocket::live</b> <i class="arg">sock</i> <i class="arg">path</i> <i class="arg">cb</i> <span class="opt">?<i class="arg">proto</i>?</span></a></dt> <dd><p>This procedure registers callbacks that will be performed on a WebSocket compliant server registered with <b class="cmd">::websocket::server</b> whenever a client connects to a matching path and protocol. <i class="arg">sock</i> is the listening socket of the websocket compliant server declared using <b class="cmd">::websocket::server</b>. <i class="arg">path</i> is a glob-style path to match in client request, whenever this will occur. <i class="arg">cb</i> is the command to callback (see Callbacks). <i class="arg">proto</i> is a glob-style protocol name matcher.</p></dd> <dt><a name="5"><b class="cmd">::websocket::test</b> <i class="arg">srvSock</i> <i class="arg">cliSock</i> <i class="arg">path</i> <span class="opt">?<i class="arg">hdrs</i>?</span> <span class="opt">?<i class="arg">qry</i>?</span></a></dt> |
︙ | ︙ |
Changes to idoc/www/tcllib/toc.html.
︙ | ︙ | |||
765 766 767 768 769 770 771 772 773 774 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='md4'><a href="files/modules/md4/md4.html">md4</a></td> <td class="#doctools_tocright">MD4 Message-Digest Algorithm</td> </tr> | > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 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 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='md4'><a href="files/modules/md4/md4.html">md4</a></td> <td class="#doctools_tocright">MD4 Message-Digest Algorithm</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='md5'><a href="files/modules/md5/md5.html">md5</a></td> <td class="#doctools_tocright">MD5 Message-Digest Algorithm</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='md5crypt'><a href="files/modules/md5crypt/md5crypt.html">md5crypt</a></td> <td class="#doctools_tocright">MD5-based password encryption</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='mime'><a href="files/modules/mime/mime.html">mime</a></td> <td class="#doctools_tocright">Manipulation of MIME body parts</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='mpexpand'><a href="files/modules/doctools/mpexpand.html">mpexpand</a></td> <td class="#doctools_tocright">Markup processor</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='multiplexer'><a href="files/modules/multiplexer/multiplexer.html">multiplexer</a></td> <td class="#doctools_tocright">One-to-many communication with sockets.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nameserv'><a href="files/modules/nns/nns_client.html">nameserv</a></td> <td class="#doctools_tocright">Name service facility, Client</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nameserv_auto'><a href="files/modules/nns/nns_auto.html">nameserv::auto</a></td> <td class="#doctools_tocright">Name service facility, Client Extension</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nameserv_common'><a href="files/modules/nns/nns_common.html">nameserv::common</a></td> <td class="#doctools_tocright">Name service facility, shared definitions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nameserv_protocol'><a href="files/modules/nns/nns_protocol.html">nameserv::protocol</a></td> <td class="#doctools_tocright">Name service facility, client/server protocol</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nameserv_server'><a href="files/modules/nns/nns_server.html">nameserv::server</a></td> <td class="#doctools_tocright">Name service facility, Server</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='namespacex'><a href="files/modules/namespacex/namespacex.html">namespacex</a></td> <td class="#doctools_tocright">Namespace utility commands</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='ncgi'><a href="files/modules/ncgi/ncgi.html">ncgi</a></td> <td class="#doctools_tocright">Procedures to manipulate CGI values.</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nettool'><a href="files/modules/nettool/nettool.html">nettool</a></td> <td class="#doctools_tocright">Tools for networked applications</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nmea'><a href="files/modules/nmea/nmea.html">nmea</a></td> <td class="#doctools_tocright">Process NMEA data</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nns'><a href="files/apps/nns.html">nns</a></td> <td class="#doctools_tocright">Name service facility, Commandline Client Application</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nns_intro'><a href="files/modules/nns/nns_intro.html">nns_intro</a></td> <td class="#doctools_tocright">Name service facility, introduction</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nnsd'><a href="files/apps/nnsd.html">nnsd</a></td> <td class="#doctools_tocright">Name service facility, Commandline Server Application</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='nnslog'><a href="files/apps/nnslog.html">nnslog</a></td> <td class="#doctools_tocright">Name service facility, Commandline Logging Client Application</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='nntp'><a href="files/modules/nntp/nntp.html">nntp</a></td> <td class="#doctools_tocright">Tcl client for the NNTP protocol</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='ntp_time'><a href="files/modules/ntp/ntp_time.html">ntp_time</a></td> <td class="#doctools_tocright">Tcl Time Service Client</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='oauth'><a href="files/modules/oauth/oauth.html">oauth</a></td> <td class="#doctools_tocright">oauth API base signature</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='oo_util'><a href="files/modules/tool/meta.html">oo::util</a></td> <td class="#doctools_tocright">Utility commands for TclOO</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='oo_util'><a href="files/modules/ooutil/ooutil.html">oo::util</a></td> <td class="#doctools_tocright">Utility commands for TclOO</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='oometa'><a href="files/modules/oometa/oometa.html">oometa</a></td> <td class="#doctools_tocright">oo::meta A data registry for classess</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='otp'><a href="files/modules/otp/otp.html">otp</a></td> <td class="#doctools_tocright">One-Time Passwords</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='page'><a href="files/apps/page.html">page</a></td> <td class="#doctools_tocright">Parser Generator</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='page_intro'><a href="files/modules/page/page_intro.html">page_intro</a></td> <td class="#doctools_tocright">page introduction</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='page_pluginmgr'><a href="files/modules/page/page_pluginmgr.html">page_pluginmgr</a></td> <td class="#doctools_tocright">page plugin manager</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='page_util_flow'><a href="files/modules/page/page_util_flow.html">page_util_flow</a></td> <td class="#doctools_tocright">page dataflow/treewalker utility</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='page_util_norm_lemon'><a href="files/modules/page/page_util_norm_lemon.html">page_util_norm_lemon</a></td> <td class="#doctools_tocright">page AST normalization, LEMON</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='page_util_norm_peg'><a href="files/modules/page/page_util_norm_peg.html">page_util_norm_peg</a></td> <td class="#doctools_tocright">page AST normalization, PEG</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='page_util_peg'><a href="files/modules/page/page_util_peg.html">page_util_peg</a></td> <td class="#doctools_tocright">page PEG transformation utilities</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='page_util_quote'><a href="files/modules/page/page_util_quote.html">page_util_quote</a></td> <td class="#doctools_tocright">page character quoting utilities</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='picoirc'><a href="files/modules/irc/picoirc.html">picoirc</a></td> <td class="#doctools_tocright">Small and simple embeddable IRC client.</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pki'><a href="files/modules/pki/pki.html">pki</a></td> <td class="#doctools_tocright">Implementation of the public key cipher</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pluginmgr'><a href="files/modules/pluginmgr/pluginmgr.html">pluginmgr</a></td> <td class="#doctools_tocright">Manage a plugin</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='png'><a href="files/modules/png/png.html">png</a></td> <td class="#doctools_tocright">PNG querying and manipulation of meta data</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pop3'><a href="files/modules/pop3/pop3.html">pop3</a></td> <td class="#doctools_tocright">Tcl client for POP3 email protocol</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pop3d'><a href="files/modules/pop3d/pop3d.html">pop3d</a></td> <td class="#doctools_tocright">Tcl POP3 server implementation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pop3d_dbox'><a href="files/modules/pop3d/pop3d_dbox.html">pop3d::dbox</a></td> <td class="#doctools_tocright">Simple mailbox database for pop3d</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pop3d_udb'><a href="files/modules/pop3d/pop3d_udb.html">pop3d::udb</a></td> <td class="#doctools_tocright">Simple user database for pop3d</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='practcl'><a href="files/modules/practcl/practcl.html">practcl</a></td> <td class="#doctools_tocright">The Practcl Module</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='processman'><a href="files/modules/processman/processman.html">processman</a></td> <td class="#doctools_tocright">Tool for automating the period callback of commands</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='profiler'><a href="files/modules/profiler/profiler.html">profiler</a></td> <td class="#doctools_tocright">Tcl source code profiler</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt'><a href="files/apps/pt.html">pt</a></td> <td class="#doctools_tocright">Parser Tools Application</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_ast'><a href="files/modules/pt/pt_astree.html">pt::ast</a></td> <td class="#doctools_tocright">Abstract Syntax Tree Serialization</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_cparam_configuration_critcl'><a href="files/modules/pt/pt_cparam_config_critcl.html">pt::cparam::configuration::critcl</a></td> <td class="#doctools_tocright">C/PARAM, Canned configuration, Critcl</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_cparam_configuration_tea'><a href="files/modules/pt/pt_cparam_config_tea.html">pt::cparam::configuration::tea</a></td> <td class="#doctools_tocright">C/PARAM, Canned configuration, TEA</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_json_language'><a href="files/modules/pt/pt_json_language.html">pt::json_language</a></td> <td class="#doctools_tocright">The JSON Grammar Exchange Format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_param'><a href="files/modules/pt/pt_param.html">pt::param</a></td> <td class="#doctools_tocright">PackRat Machine Specification</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_pe'><a href="files/modules/pt/pt_pexpression.html">pt::pe</a></td> <td class="#doctools_tocright">Parsing Expression Serialization</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_pe_op'><a href="files/modules/pt/pt_pexpr_op.html">pt::pe::op</a></td> <td class="#doctools_tocright">Parsing Expression Utilities</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg'><a href="files/modules/pt/pt_pegrammar.html">pt::peg</a></td> <td class="#doctools_tocright">Parsing Expression Grammar Serialization</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_container'><a href="files/modules/pt/pt_peg_container.html">pt::peg::container</a></td> <td class="#doctools_tocright">PEG Storage</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_container_peg'><a href="files/modules/pt/pt_peg_container_peg.html">pt::peg::container::peg</a></td> <td class="#doctools_tocright">PEG Storage. Canned PEG grammar specification</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_export'><a href="files/modules/pt/pt_peg_export.html">pt::peg::export</a></td> <td class="#doctools_tocright">PEG Export</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_export_container'><a href="files/modules/pt/pt_peg_export_container.html">pt::peg::export::container</a></td> <td class="#doctools_tocright">PEG Export Plugin. Write CONTAINER format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_export_json'><a href="files/modules/pt/pt_peg_export_json.html">pt::peg::export::json</a></td> <td class="#doctools_tocright">PEG Export Plugin. Write JSON format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_export_peg'><a href="files/modules/pt/pt_peg_export_peg.html">pt::peg::export::peg</a></td> <td class="#doctools_tocright">PEG Export Plugin. Write PEG format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_from_container'><a href="files/modules/pt/pt_peg_from_container.html">pt::peg::from::container</a></td> <td class="#doctools_tocright">PEG Conversion. From CONTAINER format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_from_json'><a href="files/modules/pt/pt_peg_from_json.html">pt::peg::from::json</a></td> <td class="#doctools_tocright">PEG Conversion. Read JSON format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_from_peg'><a href="files/modules/pt/pt_peg_from_peg.html">pt::peg::from::peg</a></td> <td class="#doctools_tocright">PEG Conversion. Read PEG format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_import'><a href="files/modules/pt/pt_peg_import.html">pt::peg::import</a></td> <td class="#doctools_tocright">PEG Import</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_import_container'><a href="files/modules/pt/pt_peg_import_container.html">pt::peg::import::container</a></td> <td class="#doctools_tocright">PEG Import Plugin. From CONTAINER format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_import_json'><a href="files/modules/pt/pt_peg_import_json.html">pt::peg::import::json</a></td> <td class="#doctools_tocright">PEG Import Plugin. Read JSON format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_import_peg'><a href="files/modules/pt/pt_peg_import_peg.html">pt::peg::import::peg</a></td> <td class="#doctools_tocright">PEG Import Plugin. Read PEG format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_interp'><a href="files/modules/pt/pt_peg_interp.html">pt::peg::interp</a></td> <td class="#doctools_tocright">Interpreter for parsing expression grammars</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_to_container'><a href="files/modules/pt/pt_peg_to_container.html">pt::peg::to::container</a></td> <td class="#doctools_tocright">PEG Conversion. Write CONTAINER format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_to_cparam'><a href="files/modules/pt/pt_peg_to_cparam.html">pt::peg::to::cparam</a></td> <td class="#doctools_tocright">PEG Conversion. Write CPARAM format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_to_json'><a href="files/modules/pt/pt_peg_to_json.html">pt::peg::to::json</a></td> <td class="#doctools_tocright">PEG Conversion. Write JSON format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_to_param'><a href="files/modules/pt/pt_peg_to_param.html">pt::peg::to::param</a></td> <td class="#doctools_tocright">PEG Conversion. Write PARAM format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_to_peg'><a href="files/modules/pt/pt_peg_to_peg.html">pt::peg::to::peg</a></td> <td class="#doctools_tocright">PEG Conversion. Write PEG format</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_to_tclparam'><a href="files/modules/pt/pt_peg_to_tclparam.html">pt::peg::to::tclparam</a></td> <td class="#doctools_tocright">PEG Conversion. Write TCLPARAM format</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_peg_language'><a href="files/modules/pt/pt_peg_language.html">pt::peg_language</a></td> <td class="#doctools_tocright">PEG Language Tutorial</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_pegrammar'><a href="files/modules/pt/pt_peg_introduction.html">pt::pegrammar</a></td> <td class="#doctools_tocright">Introduction to Parsing Expression Grammars</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_pgen'><a href="files/modules/pt/pt_pgen.html">pt::pgen</a></td> <td class="#doctools_tocright">Parser Generator</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_rde'><a href="files/modules/pt/pt_rdengine.html">pt::rde</a></td> <td class="#doctools_tocright">Parsing Runtime Support, PARAM based</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_tclparam_configuration_nx'><a href="files/modules/pt/pt_tclparam_config_nx.html">pt::tclparam::configuration::nx</a></td> <td class="#doctools_tocright">Tcl/PARAM, Canned configuration, NX</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_tclparam_configuration_snit'><a href="files/modules/pt/pt_tclparam_config_snit.html">pt::tclparam::configuration::snit</a></td> <td class="#doctools_tocright">Tcl/PARAM, Canned configuration, Snit</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_tclparam_configuration_tcloo'><a href="files/modules/pt/pt_tclparam_config_tcloo.html">pt::tclparam::configuration::tcloo</a></td> <td class="#doctools_tocright">Tcl/PARAM, Canned configuration, Tcloo</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_util'><a href="files/modules/pt/pt_util.html">pt::util</a></td> <td class="#doctools_tocright">General utilities</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_export_api'><a href="files/modules/pt/pt_to_api.html">pt_export_api</a></td> <td class="#doctools_tocright">Parser Tools Export API</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_import_api'><a href="files/modules/pt/pt_from_api.html">pt_import_api</a></td> <td class="#doctools_tocright">Parser Tools Import API</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_introduction'><a href="files/modules/pt/pt_introduction.html">pt_introduction</a></td> <td class="#doctools_tocright">Introduction to Parser Tools</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_parse_peg'><a href="files/modules/pt/pt_parse_peg.html">pt_parse_peg</a></td> <td class="#doctools_tocright">Parser Tools PEG Parser</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='pt_parser_api'><a href="files/modules/pt/pt_parser_api.html">pt_parser_api</a></td> <td class="#doctools_tocright">Parser API</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='pt_peg_op'><a href="files/modules/pt/pt_peg_op.html">pt_peg_op</a></td> <td class="#doctools_tocright">Parser Tools PE Grammar Utility Operations</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='rc4'><a href="files/modules/rc4/rc4.html">rc4</a></td> <td class="#doctools_tocright">Implementation of the RC4 stream cipher</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='rcs'><a href="files/modules/rcs/rcs.html">rcs</a></td> <td class="#doctools_tocright">RCS low level utilities</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='report'><a href="files/modules/report/report.html">report</a></td> <td class="#doctools_tocright">Create and manipulate report objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='rest'><a href="files/modules/rest/rest.html">rest</a></td> <td class="#doctools_tocright">define REST web APIs and call them inline or asychronously</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='ripemd128'><a href="files/modules/ripemd/ripemd128.html">ripemd128</a></td> <td class="#doctools_tocright">RIPEMD-128 Message-Digest Algorithm</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='ripemd160'><a href="files/modules/ripemd/ripemd160.html">ripemd160</a></td> <td class="#doctools_tocright">RIPEMD-160 Message-Digest Algorithm</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='s3'><a href="files/modules/amazon-s3/S3.html">S3</a></td> <td class="#doctools_tocright">Amazon S3 Web Service Interface</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='sasl'><a href="files/modules/sasl/sasl.html">SASL</a></td> <td class="#doctools_tocright">Implementation of SASL mechanisms for Tcl</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='sasl_ntlm'><a href="files/modules/sasl/ntlm.html">SASL::NTLM</a></td> <td class="#doctools_tocright">Implementation of SASL NTLM mechanism for Tcl</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='sasl_scram'><a href="files/modules/sasl/scram.html">SASL::SCRAM</a></td> <td class="#doctools_tocright">Implementation of SASL SCRAM mechanism for Tcl</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='sasl_xgoogletoken'><a href="files/modules/sasl/gtoken.html">SASL::XGoogleToken</a></td> <td class="#doctools_tocright">Implementation of SASL NTLM mechanism for Tcl</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='sha1'><a href="files/modules/sha1/sha1.html">sha1</a></td> <td class="#doctools_tocright">SHA1 Message-Digest Algorithm</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='sha256'><a href="files/modules/sha1/sha256.html">sha256</a></td> <td class="#doctools_tocright">SHA256 Message-Digest Algorithm</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_montecarlo'><a href="files/modules/simulation/montecarlo.html">simulation::montecarlo</a></td> <td class="#doctools_tocright">Monte Carlo simulations</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_random'><a href="files/modules/simulation/simulation_random.html">simulation::random</a></td> <td class="#doctools_tocright">Pseudo-random number generators</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='smtp'><a href="files/modules/mime/smtp.html">smtp</a></td> <td class="#doctools_tocright">Client-side tcl implementation of the smtp protocol</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='smtpd'><a href="files/modules/smtpd/smtpd.html">smtpd</a></td> <td class="#doctools_tocright">Tcl SMTP server implementation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='snit'><a href="files/modules/snit/snit.html">snit</a></td> <td class="#doctools_tocright">Snit's Not Incr Tcl</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='snitfaq'><a href="files/modules/snit/snitfaq.html">snitfaq</a></td> <td class="#doctools_tocright">Snit Frequently Asked Questions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='soundex'><a href="files/modules/soundex/soundex.html">soundex</a></td> <td class="#doctools_tocright">Soundex</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='stooop'><a href="files/modules/stooop/stooop.html">stooop</a></td> <td class="#doctools_tocright">Object oriented extension.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='string_token'><a href="files/modules/string/token.html">string::token</a></td> <td class="#doctools_tocright">Regex based iterative lexing</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='string_token_shell'><a href="files/modules/string/token_shell.html">string::token::shell</a></td> <td class="#doctools_tocright">Parsing of shell command line</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='stringprep'><a href="files/modules/stringprep/stringprep.html">stringprep</a></td> <td class="#doctools_tocright">Implementation of stringprep</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='stringprep_data'><a href="files/modules/stringprep/stringprep_data.html">stringprep::data</a></td> <td class="#doctools_tocright">stringprep data tables, generated, internal</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_disjointset'><a href="files/modules/struct/disjointset.html">struct::disjointset</a></td> <td class="#doctools_tocright">Disjoint set data structure</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_graph'><a href="files/modules/struct/graph.html">struct::graph</a></td> <td class="#doctools_tocright">Create and manipulate directed graph objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_graph_op'><a href="files/modules/struct/graphops.html">struct::graph::op</a></td> <td class="#doctools_tocright">Operation for (un)directed graph objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_graph_v1'><a href="files/modules/struct/graph1.html">struct::graph_v1</a></td> <td class="#doctools_tocright">Create and manipulate directed graph objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_list'><a href="files/modules/struct/struct_list.html">struct::list</a></td> <td class="#doctools_tocright">Procedures for manipulating lists</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_matrix'><a href="files/modules/struct/matrix.html">struct::matrix</a></td> <td class="#doctools_tocright">Create and manipulate matrix objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_matrix_v1'><a href="files/modules/struct/matrix1.html">struct::matrix_v1</a></td> <td class="#doctools_tocright">Create and manipulate matrix objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_pool'><a href="files/modules/struct/pool.html">struct::pool</a></td> <td class="#doctools_tocright">Create and manipulate pool objects (of discrete items)</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_prioqueue'><a href="files/modules/struct/prioqueue.html">struct::prioqueue</a></td> <td class="#doctools_tocright">Create and manipulate prioqueue objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_queue'><a href="files/modules/struct/queue.html">struct::queue</a></td> <td class="#doctools_tocright">Create and manipulate queue objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_record'><a href="files/modules/struct/record.html">struct::record</a></td> <td class="#doctools_tocright">Define and create records (similar to 'C' structures)</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_set'><a href="files/modules/struct/struct_set.html">struct::set</a></td> <td class="#doctools_tocright">Procedures for manipulating sets</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_skiplist'><a href="files/modules/struct/skiplist.html">struct::skiplist</a></td> <td class="#doctools_tocright">Create and manipulate skiplists</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_stack'><a href="files/modules/struct/stack.html">struct::stack</a></td> <td class="#doctools_tocright">Create and manipulate stack objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='struct_tree'><a href="files/modules/struct/struct_tree.html">struct::tree</a></td> <td class="#doctools_tocright">Create and manipulate tree objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='struct_tree_v1'><a href="files/modules/struct/struct_tree1.html">struct::tree_v1</a></td> <td class="#doctools_tocright">Create and manipulate tree objects</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='sum'><a href="files/modules/crc/sum.html">sum</a></td> <td class="#doctools_tocright">Calculate a sum(1) compatible checksum</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='switched'><a href="files/modules/stooop/switched.html">switched</a></td> <td class="#doctools_tocright">switch/option management.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tar'><a href="files/modules/tar/tar.html">tar</a></td> <td class="#doctools_tocright">Tar file creation, extraction & manipulation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_cat'><a href="files/modules/virtchannel_base/cat.html">tcl::chan::cat</a></td> <td class="#doctools_tocright">Concatenation channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_core'><a href="files/modules/virtchannel_core/core.html">tcl::chan::core</a></td> <td class="#doctools_tocright">Basic reflected/virtual channel support</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_events'><a href="files/modules/virtchannel_core/events.html">tcl::chan::events</a></td> <td class="#doctools_tocright">Event support for reflected/virtual channels</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_facade'><a href="files/modules/virtchannel_base/facade.html">tcl::chan::facade</a></td> <td class="#doctools_tocright">Facade channel</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_fifo'><a href="files/modules/virtchannel_base/tcllib_fifo.html">tcl::chan::fifo</a></td> <td class="#doctools_tocright">In-memory fifo channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_fifo2'><a href="files/modules/virtchannel_base/tcllib_fifo2.html">tcl::chan::fifo2</a></td> <td class="#doctools_tocright">In-memory interconnected fifo channels</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_halfpipe'><a href="files/modules/virtchannel_base/halfpipe.html">tcl::chan::halfpipe</a></td> <td class="#doctools_tocright">In-memory channel, half of a fifo2</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_memchan'><a href="files/modules/virtchannel_base/tcllib_memchan.html">tcl::chan::memchan</a></td> <td class="#doctools_tocright">In-memory channel</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_null'><a href="files/modules/virtchannel_base/tcllib_null.html">tcl::chan::null</a></td> <td class="#doctools_tocright">Null channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_nullzero'><a href="files/modules/virtchannel_base/nullzero.html">tcl::chan::nullzero</a></td> <td class="#doctools_tocright">Null/Zero channel combination</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_random'><a href="files/modules/virtchannel_base/tcllib_random.html">tcl::chan::random</a></td> <td class="#doctools_tocright">Random channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_std'><a href="files/modules/virtchannel_base/std.html">tcl::chan::std</a></td> <td class="#doctools_tocright">Standard I/O, unification of stdin and stdout</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_string'><a href="files/modules/virtchannel_base/tcllib_string.html">tcl::chan::string</a></td> <td class="#doctools_tocright">Read-only in-memory channel</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_textwindow'><a href="files/modules/virtchannel_base/textwindow.html">tcl::chan::textwindow</a></td> <td class="#doctools_tocright">Textwindow channel</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_chan_variable'><a href="files/modules/virtchannel_base/tcllib_variable.html">tcl::chan::variable</a></td> <td class="#doctools_tocright">In-memory channel using variable for storage</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_chan_zero'><a href="files/modules/virtchannel_base/tcllib_zero.html">tcl::chan::zero</a></td> <td class="#doctools_tocright">Zero channel</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_randomseed'><a href="files/modules/virtchannel_base/randseed.html">tcl::randomseed</a></td> <td class="#doctools_tocright">Utilities for random channels</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_adler32'><a href="files/modules/virtchannel_transform/adler32.html">tcl::transform::adler32</a></td> <td class="#doctools_tocright">Adler32 transformation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_base64'><a href="files/modules/virtchannel_transform/vt_base64.html">tcl::transform::base64</a></td> <td class="#doctools_tocright">Base64 encoding transformation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_core'><a href="files/modules/virtchannel_core/transformcore.html">tcl::transform::core</a></td> <td class="#doctools_tocright">Basic reflected/virtual channel transform support</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_counter'><a href="files/modules/virtchannel_transform/vt_counter.html">tcl::transform::counter</a></td> <td class="#doctools_tocright">Counter transformation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_crc32'><a href="files/modules/virtchannel_transform/vt_crc32.html">tcl::transform::crc32</a></td> <td class="#doctools_tocright">Crc32 transformation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_hex'><a href="files/modules/virtchannel_transform/hex.html">tcl::transform::hex</a></td> <td class="#doctools_tocright">Hexadecimal encoding transformation</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_identity'><a href="files/modules/virtchannel_transform/identity.html">tcl::transform::identity</a></td> <td class="#doctools_tocright">Identity transformation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_limitsize'><a href="files/modules/virtchannel_transform/limitsize.html">tcl::transform::limitsize</a></td> <td class="#doctools_tocright">limiting input</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_observe'><a href="files/modules/virtchannel_transform/observe.html">tcl::transform::observe</a></td> <td class="#doctools_tocright">Observer transformation, stream copy</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_otp'><a href="files/modules/virtchannel_transform/vt_otp.html">tcl::transform::otp</a></td> <td class="#doctools_tocright">Encryption via one-time pad</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_rot'><a href="files/modules/virtchannel_transform/rot.html">tcl::transform::rot</a></td> <td class="#doctools_tocright">rot-encryption</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcl_transform_spacer'><a href="files/modules/virtchannel_transform/spacer.html">tcl::transform::spacer</a></td> <td class="#doctools_tocright">Space insertation and removal</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcl_transform_zlib'><a href="files/modules/virtchannel_transform/tcllib_zlib.html">tcl::transform::zlib</a></td> <td class="#doctools_tocright">zlib (de)compression</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcldes'><a href="files/modules/des/tcldes.html">tclDES</a></td> <td class="#doctools_tocright">Implementation of the DES and triple-DES ciphers</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcldesjr'><a href="files/modules/des/tcldesjr.html">tclDESjr</a></td> <td class="#doctools_tocright">Implementation of the DES and triple-DES ciphers</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tcldocstrip'><a href="files/apps/tcldocstrip.html">tcldocstrip</a></td> <td class="#doctools_tocright">Tcl-based Docstrip Processor</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tcllib_ip'><a href="files/modules/dns/tcllib_ip.html">tcllib_ip</a></td> <td class="#doctools_tocright">IPv4 and IPv6 address manipulation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tepam'><a href="files/modules/tepam/tepam_introduction.html">tepam</a></td> <td class="#doctools_tocright">An introduction into TEPAM, Tcl's Enhanced Procedure and Argument Manager</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tepam_argument_dialogbox'><a href="files/modules/tepam/tepam_argument_dialogbox.html">tepam::argument_dialogbox</a></td> <td class="#doctools_tocright">TEPAM argument_dialogbox, reference manual</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tepam_doc_gen'><a href="files/modules/tepam/tepam_doc_gen.html">tepam::doc_gen</a></td> <td class="#doctools_tocright">TEPAM DOC Generation, reference manual</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tepam_procedure'><a href="files/modules/tepam/tepam_procedure.html">tepam::procedure</a></td> <td class="#doctools_tocright">TEPAM procedure, reference manual</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term'><a href="files/modules/term/term.html">term</a></td> <td class="#doctools_tocright">General terminal control</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_ansi_code'><a href="files/modules/term/ansi_code.html">term::ansi::code</a></td> <td class="#doctools_tocright">Helper for control sequences</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_ansi_code_attr'><a href="files/modules/term/ansi_cattr.html">term::ansi::code::attr</a></td> <td class="#doctools_tocright">ANSI attribute sequences</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_ansi_code_ctrl'><a href="files/modules/term/ansi_cctrl.html">term::ansi::code::ctrl</a></td> <td class="#doctools_tocright">ANSI control sequences</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_ansi_code_macros'><a href="files/modules/term/ansi_cmacros.html">term::ansi::code::macros</a></td> <td class="#doctools_tocright">Macro sequences</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_ansi_ctrl_unix'><a href="files/modules/term/ansi_ctrlu.html">term::ansi::ctrl::unix</a></td> <td class="#doctools_tocright">Control operations and queries</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_ansi_send'><a href="files/modules/term/ansi_send.html">term::ansi::send</a></td> <td class="#doctools_tocright">Output of ANSI control sequences to terminals</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_interact_menu'><a href="files/modules/term/imenu.html">term::interact::menu</a></td> <td class="#doctools_tocright">Terminal widget, menu</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_interact_pager'><a href="files/modules/term/ipager.html">term::interact::pager</a></td> <td class="#doctools_tocright">Terminal widget, paging</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_receive'><a href="files/modules/term/receive.html">term::receive</a></td> <td class="#doctools_tocright">General input from terminals</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='term_receive_bind'><a href="files/modules/term/term_bind.html">term::receive::bind</a></td> <td class="#doctools_tocright">Keyboard dispatch from terminals</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='term_send'><a href="files/modules/term/term_send.html">term::send</a></td> <td class="#doctools_tocright">General output to terminals</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='textutil'><a href="files/modules/textutil/textutil.html">textutil</a></td> <td class="#doctools_tocright">Procedures to manipulate texts and strings.</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='textutil_adjust'><a href="files/modules/textutil/adjust.html">textutil::adjust</a></td> <td class="#doctools_tocright">Procedures to adjust, indent, and undent paragraphs</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='textutil_expander'><a href="files/modules/textutil/expander.html">textutil::expander</a></td> <td class="#doctools_tocright">Procedures to process templates and expand text.</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='textutil_repeat'><a href="files/modules/textutil/repeat.html">textutil::repeat</a></td> <td class="#doctools_tocright">Procedures to repeat strings.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='textutil_split'><a href="files/modules/textutil/textutil_split.html">textutil::split</a></td> <td class="#doctools_tocright">Procedures to split texts</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='textutil_string'><a href="files/modules/textutil/textutil_string.html">textutil::string</a></td> <td class="#doctools_tocright">Procedures to manipulate texts and strings.</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='textutil_tabify'><a href="files/modules/textutil/tabify.html">textutil::tabify</a></td> <td class="#doctools_tocright">Procedures to (un)tabify strings</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='textutil_trim'><a href="files/modules/textutil/trim.html">textutil::trim</a></td> <td class="#doctools_tocright">Procedures to trim strings</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='throw'><a href="files/modules/try/tcllib_throw.html">throw</a></td> <td class="#doctools_tocright">throw - Throw an error exception with a message</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tie'><a href="files/modules/tie/tie_std.html">tie</a></td> <td class="#doctools_tocright">Array persistence, standard data sources</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tie'><a href="files/modules/tie/tie.html">tie</a></td> <td class="#doctools_tocright">Array persistence</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tiff'><a href="files/modules/tiff/tiff.html">tiff</a></td> <td class="#doctools_tocright">TIFF reading, writing, and querying and manipulation of meta data</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tool'><a href="files/modules/httpd/httpd.html">tool</a></td> <td class="#doctools_tocright">A TclOO and coroutine based web server</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tool'><a href="files/modules/tool/tool.html">tool</a></td> <td class="#doctools_tocright">TclOO Library (TOOL) Framework</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tool_dict_ensemble'><a href="files/modules/tool/tool_dict_ensemble.html">tool::dict_ensemble</a></td> <td class="#doctools_tocright">Dictionary Tools</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='transfer_connect'><a href="files/modules/transfer/connect.html">transfer::connect</a></td> <td class="#doctools_tocright">Connection setup</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='transfer_copy'><a href="files/modules/transfer/copyops.html">transfer::copy</a></td> <td class="#doctools_tocright">Data transfer foundation</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='transfer_copy_queue'><a href="files/modules/transfer/tqueue.html">transfer::copy::queue</a></td> <td class="#doctools_tocright">Queued transfers</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='transfer_data_destination'><a href="files/modules/transfer/ddest.html">transfer::data::destination</a></td> <td class="#doctools_tocright">Data destination</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='transfer_data_source'><a href="files/modules/transfer/dsource.html">transfer::data::source</a></td> <td class="#doctools_tocright">Data source</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='transfer_receiver'><a href="files/modules/transfer/receiver.html">transfer::receiver</a></td> <td class="#doctools_tocright">Data source</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='transfer_transmitter'><a href="files/modules/transfer/transmitter.html">transfer::transmitter</a></td> <td class="#doctools_tocright">Data source</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='treeql'><a href="files/modules/treeql/treeql.html">treeql</a></td> <td class="#doctools_tocright">Query tree objects</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='try'><a href="files/modules/try/tcllib_try.html">try</a></td> <td class="#doctools_tocright">try - Trap and process errors and exceptions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='udpcluster'><a href="files/modules/udpcluster/udpcluster.html">udpcluster</a></td> <td class="#doctools_tocright">UDP Peer-to-Peer cluster</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='uevent'><a href="files/modules/uev/uevent.html">uevent</a></td> <td class="#doctools_tocright">User events</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='uevent_onidle'><a href="files/modules/uev/uevent_onidle.html">uevent::onidle</a></td> <td class="#doctools_tocright">Request merging and deferal to idle time</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='unicode'><a href="files/modules/stringprep/unicode.html">unicode</a></td> <td class="#doctools_tocright">Implementation of Unicode normalization</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='unicode_data'><a href="files/modules/stringprep/unicode_data.html">unicode::data</a></td> <td class="#doctools_tocright">unicode data tables, generated, internal</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='units'><a href="files/modules/units/units.html">units</a></td> <td class="#doctools_tocright">unit conversion</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='uri'><a href="files/modules/uri/uri.html">uri</a></td> <td class="#doctools_tocright">URI utilities</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='uri_urn'><a href="files/modules/uri/urn-scheme.html">uri_urn</a></td> <td class="#doctools_tocright">URI utilities, URN scheme</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='uuencode'><a href="files/modules/base64/uuencode.html">uuencode</a></td> <td class="#doctools_tocright">UU-encode/decode binary data</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='uuid'><a href="files/modules/uuid/uuid.html">uuid</a></td> <td class="#doctools_tocright">UUID generation and comparison</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_common'><a href="files/modules/valtype/valtype_common.html">valtype::common</a></td> <td class="#doctools_tocright">Validation, common code</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_creditcard_amex'><a href="files/modules/valtype/cc_amex.html">valtype::creditcard::amex</a></td> <td class="#doctools_tocright">Validation for AMEX creditcard number</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_creditcard_discover'><a href="files/modules/valtype/cc_discover.html">valtype::creditcard::discover</a></td> <td class="#doctools_tocright">Validation for Discover creditcard number</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_creditcard_mastercard'><a href="files/modules/valtype/cc_mastercard.html">valtype::creditcard::mastercard</a></td> <td class="#doctools_tocright">Validation for Mastercard creditcard number</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_creditcard_visa'><a href="files/modules/valtype/cc_visa.html">valtype::creditcard::visa</a></td> <td class="#doctools_tocright">Validation for VISA creditcard number</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_gs1_ean13'><a href="files/modules/valtype/ean13.html">valtype::gs1::ean13</a></td> <td class="#doctools_tocright">Validation for EAN13</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_iban'><a href="files/modules/valtype/iban.html">valtype::iban</a></td> <td class="#doctools_tocright">Validation for IBAN</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_imei'><a href="files/modules/valtype/imei.html">valtype::imei</a></td> <td class="#doctools_tocright">Validation for IMEI</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_isbn'><a href="files/modules/valtype/isbn.html">valtype::isbn</a></td> <td class="#doctools_tocright">Validation for ISBN</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_luhn'><a href="files/modules/valtype/luhn.html">valtype::luhn</a></td> <td class="#doctools_tocright">Validation for plain number with a LUHN checkdigit</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_luhn5'><a href="files/modules/valtype/luhn5.html">valtype::luhn5</a></td> <td class="#doctools_tocright">Validation for plain number with a LUHN5 checkdigit</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='valtype_usnpi'><a href="files/modules/valtype/usnpi.html">valtype::usnpi</a></td> <td class="#doctools_tocright">Validation for USNPI</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='valtype_verhoeff'><a href="files/modules/valtype/verhoeff.html">valtype::verhoeff</a></td> <td class="#doctools_tocright">Validation for plain number with a VERHOEFF checkdigit</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='websocket'><a href="files/modules/websocket/websocket.html">websocket</a></td> <td class="#doctools_tocright">Tcl implementation of the websocket protocol</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='wip'><a href="files/modules/wip/wip.html">wip</a></td> <td class="#doctools_tocright">Word Interpreter</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='xsxp'><a href="files/modules/amazon-s3/xsxp.html">xsxp</a></td> <td class="#doctools_tocright">eXtremely Simple Xml Parser</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='yaml'><a href="files/modules/yaml/yaml.html">yaml</a></td> <td class="#doctools_tocright">YAML Format Encoder/Decoder</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='yencode'><a href="files/modules/base64/yencode.html">yencode</a></td> <td class="#doctools_tocright">Y-encode/decode binary data</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='zipfile_decode'><a href="files/modules/zip/decode.html">zipfile::decode</a></td> <td class="#doctools_tocright">Access to zip archives</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='zipfile_encode'><a href="files/modules/zip/encode.html">zipfile::encode</a></td> <td class="#doctools_tocright">Generation of zip archives</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='zipfile_mkzip'><a href="files/modules/zip/mkzip.html">zipfile::mkzip</a></td> <td class="#doctools_tocright">Build a zip archive</td> </tr> </table> </dl><hr></body></html> |
Changes to idoc/www/toc.html.
︙ | ︙ | |||
811 812 813 814 815 816 817 818 819 820 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="tcllib/files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> | > > > > | | | 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 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="tcllib/files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="tcllib/files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_montecarlo'><a href="tcllib/files/modules/simulation/montecarlo.html">simulation::montecarlo</a></td> <td class="#doctools_tocright">Monte Carlo simulations</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_random'><a href="tcllib/files/modules/simulation/simulation_random.html">simulation::random</a></td> <td class="#doctools_tocright">Pseudo-random number generators</td> </tr> </table></dl> <dl><dt><a name='networking'>Networking<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > |
︙ | ︙ | |||
2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="tcllib/files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> </table></dl> <dl><dt><a name='md4'>md4<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > | > > > > | 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="tcllib/files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="tcllib/files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> </table></dl> <dl><dt><a name='md4'>md4<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > |
︙ | ︙ |
Changes to idoc/www/toc0.html.
︙ | ︙ | |||
811 812 813 814 815 816 817 818 819 820 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="tcllib/files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> | > > > > | | | 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 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="tcllib/files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_annealing'><a href="tcllib/files/modules/simulation/annealing.html">simulation::annealing</a></td> <td class="#doctools_tocright">Simulated annealing</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='simulation_montecarlo'><a href="tcllib/files/modules/simulation/montecarlo.html">simulation::montecarlo</a></td> <td class="#doctools_tocright">Monte Carlo simulations</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='simulation_random'><a href="tcllib/files/modules/simulation/simulation_random.html">simulation::random</a></td> <td class="#doctools_tocright">Pseudo-random number generators</td> </tr> </table></dl> <dl><dt><a name='networking'>Networking<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > |
︙ | ︙ |
Changes to idoc/www/toc1.html.
︙ | ︙ | |||
980 981 982 983 984 985 986 987 988 989 990 991 992 993 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="tcllib/files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> </table></dl> <dl><dt><a name='md4'>md4<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > | > > > > | 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 | <td class="#doctools_tocright">Special mathematical functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='math_statistics'><a href="tcllib/files/modules/math/statistics.html">math::statistics</a></td> <td class="#doctools_tocright">Basic statistical functions and procedures</td> </tr> <tr class="#doctools_toceven" > <td class="#doctools_tocleft" ><a name='math_trig'><a href="tcllib/files/modules/math/trig.html">math::trig</a></td> <td class="#doctools_tocright">Trigonometric anf hyperbolic functions</td> </tr> <tr class="#doctools_tocodd" > <td class="#doctools_tocleft" ><a name='tclrep_machineparameters'><a href="tcllib/files/modules/math/machineparameters.html">tclrep/machineparameters</a></td> <td class="#doctools_tocright">Compute double precision machine parameters.</td> </tr> </table></dl> <dl><dt><a name='md4'>md4<dd> <table class="#doctools_toc"> <tr class="#doctools_toceven" > |
︙ | ︙ |
Added modules/clay/build/build.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | set srcdir [file dirname [file normalize [file join [pwd] [info script]]]] set moddir [file dirname $srcdir] set version 0.3 set module clay set filename clay source [file join $srcdir doctool.tcl] ::clay::doctool create AutoDoc set fout [open [file join $moddir ${filename}.tcl] w] dict set modmap %module% $module dict set modmap %version% $version dict set modmap %license% BSD dict set modmap %filename% $filename set authors {{Sean Woods} {<[email protected]>}} puts $fout [string map $modmap {### # %filename%.tcl # # Copyright (c) 2018 Sean Woods # # BSD License ### # @@ Meta Begin # Package %module% %version% # Meta platform tcl # Meta summary A minimalist framework for complex TclOO development # Meta description This package introduces the method "clay" to both oo::object # Meta description and oo::class which facilitate complex interactions between objects # Meta description and their ancestor and mixed in classes. # Meta category TclOO # Meta subject framework # Meta require {Tcl 8.6}}] foreach {name email} $authors { puts $fout "# Meta author $name" } puts $fout [string map $modmap {# Meta license %license% # @@ Meta End }] puts $fout [string map $modmap {### # Amalgamated package for %module% # Do not edit directly, tweak the source in build/ and rerun # build.tcl ### package provide %module% %version% namespace eval ::%module% {} }] # Track what files we have included so far set loaded {} lappend loaded build.tcl test.tcl # These files must be loaded in a particular order foreach file { core.tcl procs.tcl class.tcl object.tcl metaclass.tcl ensemble.tcl } { lappend loaded $file set content [::clay::cat [file join $srcdir {*}$file]] AutoDoc scan_text $content puts $fout "###\n# START: [file tail $file]\n###" puts $fout [::clay::docstrip $content] puts $fout "###\n# END: [file tail $file]\n###" } # These files can be loaded in any order foreach file [lsort -dictionary [glob [file join $srcdir *.tcl]]] { if {[file tail $file] in $loaded} continue lappend loaded $file set content [::clay::cat [file join $srcdir {*}$file]] AutoDoc scan_text $content puts $fout "###\n# START: [file tail $file]\n###" puts $fout [::clay::docstrip $content] puts $fout "###\n# END: [file tail $file]\n###" } # Provide some cleanup and our final package provide puts $fout [string map $modmap { namespace eval ::%module% { namespace export * } }] close $fout ### # Build our pkgIndex.tcl file ### set fout [open [file join $moddir pkgIndex.tcl] w] puts $fout [string map $modmap {# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. if {![package vsatisfies [package provide Tcl] 8.6]} {return} }] puts $fout [string map $modmap { package ifneeded %module% %version% [list source [file join $dir %module%.tcl]] }] #package ifneeded oo::meta 0.8 {package require %module% %version ; package provide oo::meta 0.8} #package ifneeded oo::option 0.4 {package require %module% %version ; package provide oo::option 0.4} puts $fout [string map $modmap { package ifneeded oo::meta 0.8 [list source [file join $dir %module%.tcl]] }] close $fout ### # Generate the test script ### namespace eval ::clay {} source [file join $srcdir procs.tcl] set fout [open [file join $moddir $filename.test] w] puts $fout [source [file join $srcdir test.tcl]] close $fout set manout [open [file join $moddir $filename.man] w] puts $manout [AutoDoc manpage \ header [string map $modmap [::clay::cat [file join $srcdir manual.txt]]] \ authors $authors \ footer [string map $modmap [::clay::cat [file join $srcdir footer.txt]]] \ ] close $manout |
Added modules/clay/build/class.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | oo::define oo::class { ### # description: # The [method clay] method allows a class object access # to a combination of its own clay data as # well as to that of its ancestors # ensemble: # ancestors { # arglist {} # description {Return this class and all ancestors in search order.} # } # dump { # arglist {} # description {Return a complete dump of this object's clay data, but only this object's clay data.} # } # get { # arglist {path {mandatory 1 positional 1 repeating 1}} # description { # Pull a chunk of data from the clay system. If the last element of [emph path] is a branch (ends in a slash /), # returns a recursive merge of all data from this object and it's constituent classes of the data in that branch. # If the last element is a leaf, search this object for a matching leaf, or search all constituent classes for a matching # leaf and return the first value found. # If no value is found, returns an empty string. # } # } # merge { # arglist {dict {mandatory 1 positional 1 repeating 1}} # description {Recursively merge the dictionaries given into the object's local clay storage.} # } # replace { # arglist {dictionary {mandatory 1 positional 1}} # description {Replace the contents of the internal clay storage with the dictionary given.} # } # search { # arglist {path {mandatory 1 positional 1 repeating 1}} # description {Return the first matching value for the path in either this class's clay data or one of its ancestors} # } # set { # arglist {path {mandatory 1 positional 1 repeating 1} value {mandatory 1 postional 1}} # description {Merge the conents of [const value] with the object's clay storage at [const path].} # } ### method clay {submethod args} { my variable clay if {![info exists clay]} { set clay {} } switch $submethod { ancestors { tailcall ::clay::ancestors [self] } exists { set path [::clay::leaf {*}$args] if {![info exists clay]} { return 0 } return [dict exists $clay {*}$path] } dump { return $clay } getnull - get { set path $args set leaf [expr {[string index [lindex $path end] end] ne "/"}] set clayorder [::clay::ancestors [self]] #puts [list [self] clay get {*}$path (leaf: $leaf)] if {$leaf} { #puts [list EXISTS: (clay) [dict exists $clay {*}$path]] if {[dict exists $clay {*}$path]} { return [dict get $clay {*}$path] } #puts [list Search in the in our list of classes for an answer] foreach class $clayorder { if {$class eq [self]} continue if {[$class clay exists {*}$path]} { set value [$class clay get {*}$path] return $value } } } else { set result {} # Leaf searches return one data field at a time # Search in our local dict # Search in the in our list of classes for an answer foreach class [lreverse $clayorder] { if {$class eq [self]} continue ::clay::dictmerge result [$class clay get {*}$path] } if {[dict exists $clay {*}$path]} { ::clay::dictmerge result [dict get $clay {*}$path] } return $result } } merge { foreach arg $args { ::clay::dictmerge clay {*}$arg } } search { foreach aclass [::clay::ancestors [self]] { if {[$aclass clay exists {*}$args]} { return [$aclass clay get {*}$args] } } } set { #puts [list [self] clay SET {*}$args] set value [lindex $args end] set path [::clay::leaf {*}[lrange $args 0 end-1]] ::clay::dictmerge clay {*}$path $value } default { dict $submethod clay {*}$args } } } } |
Added modules/clay/build/core.tcl.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | package require Tcl 8.6 ;# try in pipeline.tcl. Possibly other things. package require TclOO package require uuid package require oo::dialect ::oo::dialect::create ::clay ::namespace eval ::clay {} ::namespace eval ::clay::classes {} ::namespace eval ::clay::define {} |
Added modules/clay/build/doctool.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 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 | namespace eval ::clay {} ### # Concatenate a file ### proc ::clay::cat fname { if {![file exists $fname]} { return } set fin [open $fname r] set data [read $fin] close $fin return $data } ### # Strip the global comments from tcl code. Used to # prevent the documentation markup comments from clogging # up files intended for distribution in machine readable format. ### proc ::clay::docstrip text { set result {} foreach line [split $text \n] { append thisline $line \n if {![info complete $thisline]} continue set outline $thisline set thisline {} if {[string trim $outline] eq {}} { continue } if {[string index [string trim $outline] 0] eq "#"} continue set cmd [string trim [lindex $outline 0] :] if {$cmd eq "namespace" && [lindex $outline 1] eq "eval"} { append result [list {*}[lrange $outline 0 end-1] [docstrip [lindex $outline end]]] \n continue } if {[string match "*::define" $cmd] && [llength $outline]==3} { append result [list {*}[lrange $outline 0 end-1] [docstrip [lindex $outline end]]] \n continue } if {$cmd eq "oo::class" && [lindex $outline 1] eq "create"} { append result [list {*}[lrange $outline 0 end-1] [docstrip [lindex $outline end]]] \n continue } append result $outline } return $result } ### # Append a line of text to a variable. Optionally apply a string mapping. # arglist: # map {mandatory 0 positional 1} # text {mandatory 1 positional 1} ### proc ::putb {buffername args} { upvar 1 $buffername buffer switch [llength $args] { 1 { append buffer [lindex $args 0] \n } 2 { append buffer [string map {*}$args] \n } default { error "usage: putb buffername ?map? string" } } } ### # Tool for build scripts to dynamically generate manual files from comments # in source code files # example: # set authors { # {John Doe} {[email protected]} # {Tom RichardHarry} {[email protected]} # } # # Create the object # ::clay::doctool create AutoDoc # set fout [open [file join $moddir module.tcl] w] # foreach file [glob [file join $srcdir *.tcl]] { # set content [::clay::cat [file join $srcdir $file]] # # Scan the file # AutoDoc scan_text $content # # Strip the comments from the distribution # puts $fout [::clay::docstrip $content] # } # # Write out the manual page # set manout [open [file join $moddir module.man] w] # dict set arglist header [string map $modmap [::clay::cat [file join $srcdir manual.txt]]] # dict set arglist footer [string map $modmap [::clay::cat [file join $srcdir footer.txt]]] # dict set arglist authors $authors # puts $manout [AutoDoc manpage {*}$arglist] # close $manout ### oo::class create ::clay::doctool { constructor {} { my reset } ### # Process an argument list into an informational dict. # This method also understands non-positional # arguments expressed in the notation of Tip 471 # [uri https://core.tcl-lang.org/tips/doc/trunk/tip/479.md]. # [para] # The output will be a dictionary of all of the fields and whether the fields # are [const positional], [const mandatory], and whether they have a # [const default] value. # [para] # example: # my arglist {a b {c 10}} # # > a {positional 1 mandatory 1} b {positional 1 mandatory 1} c {positional 1 mandatory 0 default 10} ### method arglist {arglist} { set result [dict create] foreach arg $arglist { set name [lindex $arg 0] dict set result $name positional 1 dict set result $name mandatory 1 if {$name in {args dictargs}} { switch [llength $arg] { 1 { dict set result $name mandatory 0 } 2 { dict for {optname optinfo} [lindex $arg 1] { set optname [string trim $optname -:] dict set result $optname {positional 1 mandatory 0} dict for {f v} $optinfo { dict set result $optname [string trim $f -:] $v } } } default { error "Bad argument" } } } else { switch [llength $arg] { 1 { dict set result $name mandatory 1 } 2 { dict set result $name mandatory 0 dict set result $name default [lindex $arg 1] } default { error "Bad argument" } } } } return $result } ### # Convert a block of comments into an informational dictionary. # If lines in the comment start with a single word ending in a colon, # all subsequent lines are appended to a dictionary field of that name. # If no fields are given, all of the text is appended to the [const description] # field. # example: # my comment {Does something cool} # > description {Does something cool} # # my comment { # title : Something really cool # author : Sean Woods # author : John Doe # description : # This does something really cool! # } # > description {This does something really cool!} # title {Something really cool} # author {Sean Woods # John Doe} ### method comment block { set count 0 set field description set result [dict create description {}] foreach line [split $block \n] { set sline [string trim $line] set fwidx [string first " " $sline] if {$fwidx < 0} { set firstword [string range $sline 0 end] set restline {} } else { set firstword [string range $sline 0 [expr {$fwidx-1}]] set restline [string range $sline [expr {$fwidx+1}] end] } if {[string index $firstword end] eq ":"} { set field [string tolower [string trim $firstword -:]] switch $field { desc { set field description } } if {[string length $restline]} { dict append result $field "$restline\n" } } else { 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 } ### # Process an oo::define, clay::define, etc statement. ### 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 { 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 { my keyword.method info $commentblock {*}[lrange $thisline 1 end-1] set commentblock {} } } set thisline {} } dict set result class $name $info } ### # Process a statement for a clay style class method ### method keyword.class_method {resultvar commentblock name args} { upvar 1 $resultvar result set info [my comment $commentblock] if {[dict exists $info ensemble]} { dict for {method minfo} [dict get $info ensemble] { dict set result class_method "${name} $method" $minfo } } else { 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 } } ### # Process a statement for a tcloo style object method ### method keyword.method {resultvar commentblock name args} { upvar 1 $resultvar result set info [my comment $commentblock] if {[dict exists $info ensemble]} { dict for {method minfo} [dict get $info ensemble] { dict set result method "\"${name} $method\"" $minfo } } else { switch [llength $args] { 1 { set arglist [lindex $args 0] } 0 { set arglist dictargs #set body [lindex $args 0] } default {error "could not interpret method $name {*}$args"} } if {![dict exists $info arglist]} { dict set info arglist [my arglist $arglist] } dict set result method "\"[split [string trim $name :] ::]\"" $info } } ### # Process a proc statement ### method keyword.proc {commentblock name arglist body} { set info [my comment $commentblock] if {![dict exists $info arglist]} { dict set info arglist [my arglist $arglist] } return $info } ### # Reset the state of the object and its embedded coroutine ### method reset {} { my variable coro set coro [info object namespace [self]]::coro oo::objdefine [self] forward coro $coro if {[info command $coro] ne {}} { rename $coro {} } coroutine $coro {*}[namespace code {my Main}] } ### # Main body of the embedded coroutine for the object ### method Main {} { my variable info set info [dict create] yield [info coroutine] set thisline {} set commentblock {} set linec 0 while 1 { set line [yield] append thisline $line \n if {![info complete $thisline]} continue set thisline [string trim $thisline] if {[string index $thisline 0] eq "#"} { append commentblock [string trimleft $thisline #] \n set thisline {} continue } set cmd [string trim [lindex $thisline 0] ":"] switch $cmd { 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" } } tao::define - clay::define - tool::define { lassign $thisline tcmd name body my keyword.class info $commentblock $name $body set commentblock {} } oo::class { lassign $thisline tcmd mthd name body my keyword.class info $commentblock $name $body set commentblock {} } 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 {} } } ### # Generate the manual page text for a method or proc ### method section.method {keyword method minfo} { set result {} set line "\[call $keyword \[cmd $method\]" if {[dict exists $minfo arglist]} { dict for {argname arginfo} [dict get $minfo arglist] { set positional 1 set mandatory 1 set repeating 0 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 " \[emph [dict get $arginfo type]\]" } else { append line " \[emph value\]" } append line "\"" } append line "\]" if {$mandatory==0} { if {[dict exists $arginfo default]} { append line " \[const \"[dict get $arginfo default]\"\]" } append line "\"\]" } if {$repeating} { append line " \[opt \[option \"$argname...\"\]\]" } } } append line \] putb result $line if {[dict exists $minfo description]} { putb result [dict get $minfo description] } if {[dict exists $minfo example]} { putb result "\[para\]Example: \[example [list [dict get $minfo example]]\]" } return $result } ### # Generate the manual page text for a class ### 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 example}} continue putb result "\[emph \"$f\"\]: $v" putb result {[para]} } if {[dict exists $class_info example]} { putb result "\[example \{[list [dict get $class_info example]]\}\]" 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 [my section.method classmethod $method $minfo] } 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 [my section.method method $method $minfo] } putb result {[list_end]} putb result {[para]} } return $result } ### # Generate the manual page text for the commands section ### method section.command {procinfo} { set result {} putb result "\[section \{Commands\}\]" putb result {[list_begin definitions]} dict for {method minfo} $procinfo { putb result [my section.method proc $method $minfo] } putb result {[list_end]} return $result } ### # Generate the manual page. Returns the completed text suitable for saving in .man file. # The header argument is a block of doctools text to go in before the machine generated # section. footer is a block of doctools text to go in after the machine generated # section. authors is a list of individual authors and emails in the form of AUTHOR EMAIL ?AUTHOR EMAIL?... # # arglist: # header {mandatory 0 positional 0} # footer {mandatory 0 positional 0} # authors {mandatory 0 positional 0 type list} ### method manpage args { my variable info map set result {} set header {} set footer {} set authors {} dict with args {} putb result $header dict for {sec_type sec_info} $info { switch $sec_type { proc { putb result [my section.command $sec_info] } class { 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] } } } } if {[llength $authors]} { putb result {[section AUTHORS]} foreach {name email} $authors { putb result "$name \[uri mailto:$email\]\[para\]" } } putb result $footer putb result {[manpage_end]} return $result } # Scan a block of text method scan_text {text} { my variable linecount coro set linecount 0 foreach line [split $text \n] { incr linecount $coro $line } } # Scan a file of text method scan_file {filename} { my variable linecount coro set fin [open $filename r] set linecount 0 while {[gets $fin line]>=0} { incr linecount $coro $line } close $fin } } |
Added modules/clay/build/ensemble.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | ::namespace eval ::clay::define {} proc ::clay::ensemble_methodbody {ensemble einfo} { set default standard set preamble {} set eswitch {} if {[dict exists $einfo default]} { set emethodinfo [dict get $einfo default] set arglist [dict getnull $emethodinfo arglist] set realbody [dict get $emethodinfo body] if {[llength $arglist]==1 && [lindex $arglist 0] in {{} args arglist}} { set body {} } else { set body "\n ::clay::dynamic_arguments $ensemble \$method [list $arglist] {*}\$args" } append body "\n " [string trim $realbody] " \n" set default $body dict unset einfo default } foreach {msubmethod esubmethodinfo} [lsort -dictionary -stride 2 $einfo] { set submethod [string trim $msubmethod :/-] if {$submethod eq "_body"} continue if {$submethod eq "_preamble"} { set preamble [dict getnull $esubmethodinfo body] continue } set arglist [dict getnull $esubmethodinfo arglist] set realbody [dict getnull $esubmethodinfo body] if {[string length [string trim $realbody]] eq {}} { dict set eswitch $submethod {} } else { if {[llength $arglist]==1 && [lindex $arglist 0] in {{} args arglist}} { set body {} } else { set body "\n ::clay::dynamic_arguments $ensemble \$method [list $arglist] {*}\$args" } append body "\n " [string trim $realbody] " \n" if {$submethod eq "default"} { set default $body } else { dict set eswitch $submethod $body } } } set methodlist [lsort -dictionary [dict keys $eswitch]] if {![dict exists $eswitch <list>]} { dict set eswitch <list> {return $methodlist} } if {$default eq "standard"} { set default "error \"unknown method $ensemble \$method. Valid: \$methodlist\"" } dict set eswitch default $default set mbody {} append mbody $preamble \n append mbody \n [list set methodlist $methodlist] append mbody \n "set code \[catch {switch -- \$method [list $eswitch]} result opts\]" append mbody \n {return -options $opts $result} return $mbody } ::proc ::clay::define::Ensemble {rawmethod arglist body} { set class [current_class] #if {$::clay::trace>2} { # puts [list $class Ensemble $rawmethod $arglist $body] #} set mlist [split $rawmethod "::"] set ensemble [string trim [lindex $mlist 0] :/] set mensemble ${ensemble}/ if {[llength $mlist]==1 || [lindex $mlist 1] in "_body"} { set method _body ### # Simple method, needs no parsing, but we do need to record we have one ### $class clay set method_ensemble/ $mensemble _body [dict create arglist $arglist body $body] if {$::clay::trace>2} { puts [list $class clay set method_ensemble/ $mensemble _body ...] } set method $rawmethod if {$::clay::trace>2} { puts [list $class Ensemble $rawmethod $arglist $body] set rawbody $body set body {puts [list [self] $class [self method]]} append body \n $rawbody } ::oo::define $class method $rawmethod $arglist $body return } set method [join [lrange $mlist 2 end] "::"] $class clay set method_ensemble/ $mensemble [string trim $method :/] [dict create arglist $arglist body $body] if {$::clay::trace>2} { puts [list $class clay set method_ensemble/ $mensemble [string trim $method :/] ...] } } |
Added modules/clay/build/footer.txt.
> > | 1 2 | [vset CATEGORY oo] [include ../doctools2base/include/feedback.inc] |
Added modules/clay/build/manual.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | [vset VERSION %version%] [comment {-*- tcl -*- doctools manpage}] [manpage_begin %module% n [vset VERSION]] [keywords oo] [copyright {2018 Sean Woods <[email protected]>}] [moddesc {Clay Framework}] [titledesc {A minimalist framework for large scale OO Projects}] [category {Programming tools}] [keywords TclOO] [require Tcl 8.6] [require uuid] [require oo::dialect] [description] Clay introduces a method ensemble to both [class oo::class] and [class oo::object] called clay. This ensemble handles all of the high level interactions within the framework. Clay stores structured data. Clan manages method delegation. Clay has facilities to manage the complex interactions that come about with mixins. [para] The central concept is that inside of every object and class (which are actually objects too) is a dict called clay. What is stored in that dict is left to the imagination. But because this dict is exposed via a public method, we can share structured data between object, classes, and mixins. [para] [subsection {Structured Data}] Clay uses a standardized set of method interactions and introspection that TclOO already provides to perform on-the-fly searches. On-the-fly searches mean that the data is never stale, and we avoid many of the sorts of collisions that would arise when objects start mixing in other classes during operation. [para] The [method clay] methods for both classes and objects have a get and a set method. For objects, get will search through the local clay dict. If the requested leaf is not found, or the query is for a branch, the system will then begin to poll the clay methods of all of the class that implements the object, all of that classes’ ancestors, as well as all of the classes that have been mixed into this object, and all of their ancestors. [para] Intended branches on a tree end with a directory slash (/). Intended leaves are left unadorned. This is a guide for the tool that builds the search results to know what parts of a dict are intended to be branches and which are intended to be leaves. For simple cases, branch marking can be ignored: [example { ::oo::class create ::foo { } ::foo clay set property/ color blue ::foo clay set property/ shape round set A [::foo new] $A clay get property/ {color blue shape round} $A clay set property/ shape square $A clay get property/ {color blue shape square} }] [para] But when you start storing blocks of text, guessing what field is a dict and what isn’t gets messy: [example { ::foo clay set description {A generic thing of designated color and shape} $A clay get description {A generic thing of designated color and shape} Without a convention for discerning branches for leaves what should have been a value can be accidentally parsed as a dictionary, and merged with all of the other values that were never intended to be merge. Here is an example of it all going wrong: ::oo::class create ::foo { } # Add description as a leaf ::foo clay set description \ {A generic thing of designated color and shape} # Add description as a branch ::foo clay set description/ \ {A generic thing of designated color and shape} ::oo::class create ::bar { superclass foo } # Add description as a leaf ::bar clay set description \ {A drinking establishment of designated color and shape and size} # Add description as a branch ::bar clay set description/ \ {A drinking establishment of designated color and shape and size} set B [::bar new] # As a leaf we get the value verbatim from he nearest ancestor $B clay get description {A drinking establishment of designated color and shape and size} # As a branch we get a recursive merge $B clay get description/ {A drinking establishment of designated color and size thing of} }] [subsection {Clay Dialect}] Clay is built using the oo::dialect module from Tcllib. oo::dialect allows you to either add keywords directly to clay, or to create your own metaclass and keyword set using Clay as a foundation. For details on the keywords and what they do, consult the functions in the ::clay::define namespace. [subsection {Method Delegation}] Method Delegation It is sometimes useful to have an external object that can be invoked as if it were a method of the object. Clay provides a delegate ensemble method to perform that delegation, as well as introspect which methods are delegated in that manner. All delegated methods are marked with html-like tag markings (< >) around them. [example { ::clay::define counter { Variable counter 0 method incr {{howmuch 1}} { my variable counter incr counter $howmuch } method value {} { my variable counter return $counter } method reset {} { my variable counter set counter 0 } } ::clay::define example { variable buffer constructor {} { # Build a counter object set obj [namespace current]::counter ::counter create $obj # Delegate the counter my delegate <counter> $obj } method line {text} { my <counter> incr append buffer $text } } set A [example new] $A line {Who’s line is it anyway?} $A <counter> value 1 }] |
Added modules/clay/build/metaclass.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | #------------------------------------------------------------------------- # TITLE: # clay.tcl # # PROJECT: # clay: TclOO Helper Library # # DESCRIPTION: # clay(n): Implementation File # #------------------------------------------------------------------------- proc ::clay::dynamic_methods class { foreach command [info commands [namespace current]::dynamic_methods_*] { $command $class } } proc ::clay::dynamic_methods_class {thisclass} { set methods {} set mdata [$thisclass clay get class_typemethod/] foreach {method info} $mdata { set method [string trimright $method :/-] if {$method in $methods} continue lappend methods $method set arglist [dict getnull $info arglist] set body [dict getnull $info body] ::oo::objdefine $thisclass method $method $arglist $body } } ### # New OO Keywords for clay ### proc ::clay::define::Array {name {values {}}} { set class [current_class] set name [string trim $name :/]/ if {![$class clay exists array/ $name]} { $class clay set array/ $name {} } foreach {var val} $values { $class clay set array/ $name $var $val } } ### # topic: 710a93168e4ba7a971d3dbb8a3e7bcbc ### proc ::clay::define::component {name info} { set class [current_class] foreach {field value} $info { $class clay set component/ [string trim $name :/]/ $field $value } } ### # topic: 2cfc44a49f067124fda228458f77f177 # title: Specify the constructor for a class ### proc ::clay::define::constructor {arglist rawbody} { set body { my variable DestroyEvent set DestroyEvent 0 ::clay::object_create [self] [info object class [self]] # Initialize public variables and options my InitializePublic } append body $rawbody set class [current_class] ::oo::define $class constructor $arglist $body } ### # topic: 7a5c7e04989704eef117ff3c9dd88823 # title: Specify the a method for the class object itself, instead of for objects of the class ### proc ::clay::define::class_method {name arglist body} { set class [current_class] $class clay set class_typemethod/ [string trim $name :/] [dict create arglist $arglist body $body] } proc ::clay::define::clay {args} { set class [current_class] if {[lindex $args 0] in "cget set branchset"} { $class clay {*}$args } else { $class clay set {*}$args } } ### # topic: 4cb3696bf06d1e372107795de7fe1545 # title: Specify the destructor for a class ### proc ::clay::define::destructor rawbody { set body { # Run the destructor once and only once set self [self] my variable DestroyEvent if {$DestroyEvent} return set DestroyEvent 1 ::clay::object_destroy $self } append body $rawbody ::oo::define [current_class] destructor $body } proc ::clay::define::Dict {name {values {}}} { set class [current_class] set name [string trim $name :/]/ if {![$class clay exists dict/ $name]} { $class clay set dict/ $name {} } foreach {var val} $values { $class clay set dict/ $name $var $val } } ### # topic: 615b7c43b863b0d8d1f9107a8d126b21 # title: Specify a variable which should be initialized in the constructor # description: # This keyword can also be expressed: # [example {property variable NAME {default DEFAULT}}] # [para] # Variables registered in the variable property are also initialized # (if missing) when the object changes class via the [emph morph] method. ### proc ::clay::define::Variable {name {default {}}} { set class [current_class] set name [string trimright $name :/] $class clay set variable/ $name $default #::oo::define $class variable $name } proc ::clay::object_create {objname {class {}}} { #if {$::clay::trace>0} { # puts [list $objname CREATE] #} } proc ::clay::object_rename {object newname} { if {$::clay::trace>0} { puts [list $object RENAME -> $newname] } } proc ::clay::object_destroy objname { if {$::clay::trace>0} { puts [list $objname DESTROY] } ::cron::object_destroy $objname } # clay::object # # This class is inherited by all classes that have options. # ::clay::define ::clay::object { Variable clay {} Variable claycache {} Variable DestroyEvent 0 ### # Instantiate variables and build ensemble methods. ### method InitializePublic {} { next my variable clayorder clay claycache if {[info exists clay]} { set emap [dict getnull $clay method_ensemble/] } else { set emap {} } foreach class [lreverse $clayorder] { ### # Build a compsite map of all ensembles defined by the object's current # class as well as all of the classes being mixed in ### foreach {mensemble einfo} [$class clay get method_ensemble/] { set ensemble [string trim $mensemble :/] if {$::clay::trace>2} {puts [list Defining $ensemble from $class]} foreach {method info} $einfo { dict set info source $class if {$::clay::trace>2} {puts [list Defining $ensemble -> $method from $class - $info]} dict set emap $ensemble $method $info } } } foreach {ensemble einfo} $emap { #if {[dict exists $einfo _body]} continue set body [::clay::ensemble_methodbody $ensemble $einfo] if {$::clay::trace>2} { set rawbody $body set body {puts [list [self] <object> [self method]]} append body \n $rawbody } oo::objdefine [self] method $ensemble {{method default} args} $body } } } |
Added modules/clay/build/object.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 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 | oo::define oo::object { ### # description: # The [method clay] method allows an object access # to a combination of its own clay data as # well as to that of its class # ensemble: # ancestors { # arglist {} # description {Return the class this object belongs to, all classes mixed into this object, and all ancestors of those classes in search order.} # } # cget { # arglist {field {mandatory 1 positional 1}} # description { # Pull a value from either the object's clay structure or one of its constituent classes that matches the field name. # The order of search us: # [para] 1. The as a value in local dict variable config # [para] 2. The as a value in local dict variable clay # [para] 3. As a leaf in any ancestor as a root of the clay tree # [para] 4. As a leaf in any ancestor under the const/ branch of the clay tree # } # } # delegate { # arglist {stub {mandatory 0 positional 1} object {mandatory 0 positional 1}} # description { # Introspect or control method delegation. With no arguments, the method will return a # key/value list of stubs and objects. With just the [arg stub] argument, the method will # return the object (if any) attached to the stub. With a [arg stub] and an [arg object] # this command will forward all calls to the method [arg stub] to the [arg object]. # } # } # dump { arglist {} description {Return a complete dump of this object's clay data, as well as the data from all constituent classes recursively blended in.}} # ensemble_map {arglist {} description {Return a dictionary describing the method ensembles to be assembled for this object}} # eval {arglist {script {mandatory 1 positional 1}} description {Evaluated a script in the namespace of this object}} # evolve {arglist {} description {Trigger the [method InitializePublic] private method}} # exists {arglist {path {mandatory 1 positional 1 repeating 1}} description {Returns 1 if [emph path] exists in either the object's clay data. Values greater than one indicate the element exists in one of the object's constituent classes. A value of zero indicates the path could not be found.}} # flush {arglist {} description {Wipe any caches built by the clay implementation}} # forward {arglist {method {positional 1 mandatory 1} object {positional 1 mandatory 1}} description {A convenience wrapper for # [example {oo::objdefine [self] forward {*}$args}] # } # } # get {arglist {path {mandatory 1 positional 1 repeating 1}} # description {Pull a chunk of data from the clay system. If the last element of [emph path] is a branch (ends in a slash /), # returns a recursive merge of all data from this object and it's constituent classes of the data in that branch. # If the last element is a leaf, search this object for a matching leaf, or search all constituent classes for a matching # leaf and return the first value found. # If no value is found, returns an empty string. # } # } # leaf {arglist {path {mandatory 1 positional 1 repeating 1}} description {A modified get which is tailored to pull only leaf elements}} # merge {arglist {dict {mandatory 1 positional 1 repeating 1}} description {Recursively merge the dictionaries given into the object's local clay storage.}} # mixin {arglist {class {mandatory 1 positional 1 repeating 1}} description { # Perform [lb]oo::objdefine [lb]self[rb] mixin[rb] on this object, with a few additional rules: # Prior to the call, for any class was previously mixed in, but not in the new result, execute the script registered to mixin/ unmap-script (if given.) # For all new classes, that were not present prior to this call, after the native TclOO mixin is invoked, execute the script registered to mixin/ map-script (if given.) # Fall all classes that are now present and “mixed in”, execute the script registered to mixin/ react-script (if given.) # }} # mixinmap { # arglist {stub {mandatory 0 positional 1} classes {mandatory 0 positional 1}} # description {With no arguments returns the map of stubs and classes mixed into the current object. When only stub is given, # returns the classes mixed in on that stub. When stub and classlist given, replace the classes currently on that stub with the given # classes and invoke clay mixin on the new matrix of mixed in classes. # } # } # provenance {arglist {path {mandatory 1 positional 1 repeating 1}} description {Return either [const self] if that path exists in the current object, or return the first class (if any) along the clay search path which contains that element.}} # replace {arglist {dictionary {mandatory 1 positional 1}} description {Replace the contents of the internal clay storage with the dictionary given.}} # source {arglist {filename {mandatory 1 positional 1}} description {Source the given filename within the object's namespace}} # set {arglist {path {mandatory 1 positional 1 repeating 1} value {mandatory 1 postional 1}} description {Merge the conents of [const value] with the object's clay storage at [const path].}} ### method clay {submethod args} { my variable clay claycache clayorder config option_canonical if {![info exists clay]} {set clay {}} if {![info exists claycache]} {set claycache {}} if {![info exists config]} {set config {}} if {![info exists clayorder] || [llength $clayorder]==0} { set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] } switch $submethod { ancestors { return $clayorder } cget { # Leaf searches return one data field at a time # Search in our local dict if {[llength $args]==1} { set field [string trim [lindex $args 0] -:/] if {[info exists option_canonical($field)]} { set field $option_canonical($field) } if {[dict exists $config $field]} { return [dict get $config $field] } } if {[dict exists $clay {*}$args]} { return [dict get $clay {*}$args] } # Search in our local cache if {[dict exists $claycache {*}$args]} { return [dict get $claycache {*}$args] } # Search in the in our list of classes for an answer foreach class $clayorder { if {[$class clay exists {*}$args]} { set value [$class clay get {*}$args] dict set claycache {*}$args $value return $value } if {[$class clay exists const/ {*}$args]} { set value [$class clay get const/ {*}$args] dict set claycache {*}$args $value return $value } } return {} } delegate { if {![dict exists $clay delegate/ <class>]} { dict set clay delegate/ <class> [info object class [self]] } if {[llength $args]==0} { return [dict get $clay delegate/] } if {[llength $args]==1} { set stub <[string trim [lindex $args 0] <>]> if {![dict exists $clay delegate/ $stub]} { return {} } return [dict get $clay delegate/ $stub] } if {([llength $args] % 2)} { error "Usage: delegate OR delegate stub OR delegate stub OBJECT ?stub OBJECT? ..." } foreach {stub object} $args { set stub <[string trim $stub <>]> dict set clay delegate/ $stub $object oo::objdefine [self] forward ${stub} $object oo::objdefine [self] export ${stub} } } dump { # Do a full dump of clay data set result $clay # Search in the in our list of classes for an answer foreach class $clayorder { ::clay::dictmerge result [$class clay dump] } ::clay::dictmerge result $clay return $result } ensemble_map { set ensemble [lindex $args 0] my variable claycache set mensemble [string trim $ensemble :/]/ if {[dict exists $claycache method_ensemble/ $mensemble]} { return [dict get $claycache method_ensemble/ $mensemble] } set emap [my clay get method_ensemble/ $mensemble] dict set claycache method_ensemble/ $mensemble $emap return $emap } eval { set script [lindex $args 0] set buffer {} set thisline {} foreach line [split $script \n] { append thisline $line if {![info complete $thisline]} { append thisline \n continue } set thisline [string trim $thisline] if {[string index $thisline 0] eq "#"} continue if {[string length $thisline]==0} continue if {[lindex $thisline 0] eq "my"} { # Line already calls out "my", accept verbatim append buffer $thisline \n } elseif {[string range $thisline 0 2] eq "::"} { # Fully qualified commands accepted verbatim append buffer $thisline \n } elseif { append buffer "my $thisline" \n } set thisline {} } eval $buffer } evolve - initialize { my InitializePublic } exists { # Leaf searches return one data field at a time # Search in our local dict if {[dict exists $clay {*}$args]} { return 1 } # Search in our local cache if {[dict exists $claycache {*}$args]} { return 2 } set count 2 # Search in the in our list of classes for an answer foreach class $clayorder { incr count if {[$class clay exists {*}$args]} { return $count } } return 0 } flush { set claycache {} set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] } forward { oo::objdefine [self] forward {*}$args } getnull - get { set leaf [expr {[string index [lindex $args end] end] ne "/"}] #puts [list [self] clay get {*}$args (leaf: $leaf)] if {$leaf} { #puts [list EXISTS: (clay) [dict exists $clay {*}$args]] if {[dict exists $clay {*}$args]} { return [dict get $clay {*}$args] } # Search in our local cache #puts [list EXISTS: (claycache) [dict exists $claycache {*}$args]] if {[dict exists $claycache {*}$args]} { return [dict get $claycache {*}$args] } # Search in the in our list of classes for an answer foreach class $clayorder { if {[$class clay exists {*}$args]} { set value [$class clay get {*}$args] dict set claycache {*}$args $value return $value } } } else { set result {} # Leaf searches return one data field at a time # Search in our local dict # Search in the in our list of classes for an answer foreach class [lreverse $clayorder] { ::clay::dictmerge result [$class clay get {*}$args] } if {[dict exists $clay {*}$args]} { ::clay::dictmerge result [dict get $clay {*}$args] } return $result } } leaf { # Leaf searches return one data field at a time # Search in our local dict if {[dict exists $clay {*}$args]} { return [dict get $clay {*}$args] } # Search in our local cache if {[dict exists $claycache {*}$args]} { return [dict get $claycache {*}$args] } # Search in the in our list of classes for an answer foreach class $clayorder { if {[$class clay exists {*}$args]} { set value [$class clay get {*}$args] dict set claycache {*}$args $value return $value } } } merge { foreach arg $args { ::clay::dictmerge clay {*}$arg } } mixin { ### # Mix in the class ### set prior [info object mixins [self]] set newmixin {} foreach item $args { lappend newmixin ::[string trimleft $item :] } set newmap $args foreach class $prior { if {$class ni $newmixin} { set script [$class clay get mixin/ unmap-script] if {[string length $script]} { if {[catch $script err errdat]} { puts stderr "[self] MIXIN ERROR POPPING $class:\n[dict get $errdat -errorinfo]" } } } } ::oo::objdefine [self] mixin {*}$args ### # Build a compsite map of all ensembles defined by the object's current # class as well as all of the classes being mixed in ### my InitializePublic foreach class $newmixin { if {$class ni $prior} { set script [$class clay get mixin/ map-script] if {[string length $script]} { if {[catch $script err errdat]} { puts stderr "[self] MIXIN ERROR PUSHING $class:\n[dict get $errdat -errorinfo]" } } } } foreach class $newmixin { set script [$class clay search mixin/ react-script] if {[string length $script]} { if {[catch $script err errdat]} { puts stderr "[self] MIXIN ERROR PEEKING $class:\n[dict get $errdat -errorinfo]" } break } } } mixinmap { my variable clay if {![dict exists $clay mixin]} { dict set clay mixin {} } if {[llength $args]==0} { return [dict get $clay mixin] } elseif {[llength $args]==1} { return [dict getnull $clay mixin [lindex $args 0]] } else { foreach {slot classes} $args { dict set clay mixin $slot $classes } set claycache {} set classlist {} foreach {item class} [dict get $clay mixin] { if {$class ne {}} { lappend classlist $class } } my clay mixin {*}$classlist } } provenance { if {[dict exists $clay {*}$args]} { return self } foreach class $clayorder { if {[$class clay exists {*}$args]} { return $class } } return {} } replace { set clay [lindex $args 0] } source { source [lindex $args 0] } set { #puts [list [self] clay SET {*}$args] set claycache {} ::clay::dictmerge clay {*}$args } default { dict $submethod clay {*}$args } } } ### # Instantiate variables. Called on object creation and during clay mixin. ### method InitializePublic {} { my variable clayorder clay claycache config option_canonical set claycache {} set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] if {![info exists config]} { set config {} } foreach {var value} [my clay get variable/] { set var [string trim $var :/] if { $var in {clay} } continue my variable $var if {![info exists $var]} { if {$::clay::trace>2} {puts [list initialize variable $var $value]} set $var $value } } foreach {var value} [my clay get dict/] { set var [string trim $var :/] my variable $var if {![info exists $var]} { set $var {} } foreach {f v} $value { if {![dict exists ${var} $f]} { if {$::clay::trace>2} {puts [list initialize dict $var $f $v]} dict set ${var} $f $v } } } foreach {var value} [my clay get dict/] { set var [string trim $var :/] foreach {f v} [my clay get $var/] { if {![dict exists ${var} $f]} { if {$::clay::trace>2} {puts [list initialize dict (from const) $var $f $v]} dict set ${var} $f $v } } } foreach {var value} [my clay get array/] { set var [string trim $var :/] if { $var eq {clay} } continue my variable $var if {![info exists $var]} { array set $var {} } foreach {f v} $value { if {![array exists ${var}($f)]} { if {$::clay::trace>2} {puts [list initialize array $var\($f\) $v]} set ${var}($f) $v } } } foreach {var value} [my clay get array/] { set var [string trim $var :/] foreach {f v} [my clay get $var/] { if {![array exists ${var}($f)]} { if {$::clay::trace>2} {puts [list initialize array (from const) $var\($f\) $v]} set ${var}($f) $v } } } foreach {field info} [my clay get option/] { set field [string trim $field -/:] foreach alias [dict getnull $info aliases] { set option_canonical($alias) $field } if {[dict exists $config $field]} continue set getcmd [dict getnull $info default-command] if {$getcmd ne {}} { set value [{*}[string map [list %field% $field %self% [namespace which my]] $getcmd]] } else { set value [dict getnull $info default] } dict set config $field $value set setcmd [dict getnull $info set-command] if {$setcmd ne {}} { {*}[string map [list %field% [list $field] %value% [list $value] %self% [namespace which my]] $setcmd] } } } } |
Added modules/clay/build/procs.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | ### # Global utilities ### if {[info commands ::ladd] eq {}} { proc ladd {varname args} { upvar 1 $varname var if ![info exists var] { set var {} } foreach item $args { if {$item in $var} continue lappend var $item } return $var } } if {[info command ::ldelete] eq {}} { proc ::ldelete {varname args} { upvar 1 $varname var if ![info exists var] { return } foreach item [lsort -unique $args] { while {[set i [lsearch $var $item]]>=0} { set var [lreplace $var $i $i] } } return $var } } if {[info command ::lrandom] eq {}} { proc ::lrandom list { set len [llength $list] set idx [expr int(rand()*$len)] return [lindex $list $idx] } } if {[::info commands ::tcl::dict::getnull] eq {}} { proc ::tcl::dict::getnull {dictionary args} { if {[exists $dictionary {*}$args]} { get $dictionary {*}$args } } namespace ensemble configure dict -map [dict replace\ [namespace ensemble configure dict -map] getnull ::tcl::dict::getnull] } proc ::putb {buffername args} { upvar 1 $buffername buffer switch [llength $args] { 1 { append buffer [lindex $args 0] \n } 2 { append buffer [string map {*}$args] \n } default { error "usage: putb buffername ?map? string" } } } namespace eval ::clay {} set ::clay::trace 0 proc ::clay::ancestors args { set result {} set queue {} foreach class [lreverse $args] { lappend queue $class } # Rig things such that that the top superclasses # are evaluated first while {[llength $queue]} { set tqueue $queue set queue {} foreach qclass $tqueue { foreach aclass [::info class superclasses $qclass] { if { $aclass in $result } continue if { $aclass in $queue } continue lappend queue $aclass } } foreach item $tqueue { if { $item ni $result } { lappend result $item } } } return $result } proc ::clay::args_to_dict args { if {[llength $args]==1} { return [lindex $args 0] } return $args } proc ::clay::args_to_options args { set result {} foreach {var val} [args_to_dict {*}$args] { lappend result [string trim $var -:] $val } return $result } proc ::clay::dictmerge {varname args} { upvar 1 $varname result if {![info exists result]} { set result {} } switch [llength $args] { 0 { return } 1 { set result [_dictmerge $result [lindex $args 0]] return $result } 2 { lassign $args path value } default { # Merge b into a, and handle nested dicts appropriately set value [lindex $args end] set path [lrange $args 0 end-1] } } if {![dict exists $result {*}$path]} { dict set result {*}$path $value return $result } if {[string index [lindex $path end] end] ne "/"} { dict set result {*}$path $value return $result } ::dict for { k v } $value { # Element names that end in "/" are assumed to be branches if {[string index $k end] eq "/" && [::dict exists $result {*}$path $k]} { # key exists in a and b? let's see if both values are dicts # both are dicts, so merge the dicts set dvalue [::dict get $result {*}$path $k] if { [is_dict $dvalue] && [is_dict $v] } { ::dict set result {*}$path $k [_dictmerge $dvalue $v] } else { ::dict set result {*}$path $k $v } } else { ::dict set result {*}$path $k $v } } return $result } proc ::clay::_dictmerge {a b} { ::set result $a # Merge b into a, and handle nested dicts appropriately ::dict for { k v } $b { if {[string index $k end] ne "/"} { # Element names that do not end in "/" are assumed to be literals # or dict trees we intend to replace wholly ::dict set result $k $v } elseif { [::dict exists $result $k] } { # key exists in a and b? let's see if both values are dicts # both are dicts, so merge the dicts if { [is_dict [::dict get $result $k]] && [is_dict $v] } { ::dict set result $k [_dictmerge [::dict get $result $k] $v] } else { ::dict set result $k $v } } else { ::dict set result $k $v } } return $result } proc ::clay::dictputb {dict} { set result {} set level -1 _dictputb 0 $level result $dict return $result } proc ::clay::_dictputb {leaf level varname dict} { upvar 1 $varname result incr level foreach {field value} $dict { if {[string index $field end] eq "/"} { putb result "[string repeat " " $level]$field \{" _dictputb 0 $level result $value putb result "[string repeat " " $level]\}" } else { putb result "[string repeat " " $level][list $field $value]" } } } ### # topic: 4969d897a83d91a230a17f166dbcaede ### proc ::clay::dynamic_arguments {ensemble method arglist args} { set idx 0 set len [llength $args] if {$len > [llength $arglist]} { ### # Catch if the user supplies too many arguments ### set dargs 0 if {[lindex $arglist end] ni {args dictargs}} { return -code error -level 2 "Usage: $ensemble $method [string trim [dynamic_wrongargs_message $arglist]]" } } foreach argdef $arglist { if {$argdef eq "args"} { ### # Perform args processing in the style of tcl ### uplevel 1 [list set args [lrange $args $idx end]] break } if {$argdef eq "dictargs"} { ### # Perform args processing in the style of tcl ### uplevel 1 [list set args [lrange $args $idx end]] ### # Perform args processing in the style of clay ### set dictargs [::clay::args_to_options {*}[lrange $args $idx end]] uplevel 1 [list set dictargs $dictargs] break } if {$idx > $len} { ### # Catch if the user supplies too few arguments ### if {[llength $argdef]==1} { return -code error -level 2 "Usage: $ensemble $method [string trim [dynamic_wrongargs_message $arglist]]" } else { uplevel 1 [list set [lindex $argdef 0] [lindex $argdef 1]] } } else { uplevel 1 [list set [lindex $argdef 0] [lindex $args $idx]] } incr idx } } ### # topic: 53ab28ac5c6ee601fe1fe07b073be88e ### proc ::clay::dynamic_wrongargs_message {arglist} { set result "" set dargs 0 foreach argdef $arglist { if {$argdef in {args dictargs}} { set dargs 1 break } if {[llength $argdef]==1} { append result " $argdef" } else { append result " ?[lindex $argdef 0]?" } } if { $dargs } { append result " ?option value?..." } return $result } proc ::clay::is_dict { d } { # is it a dict, or can it be treated like one? if {[catch {::dict size $d} err]} { #::set ::errorInfo {} return 0 } return 1 } proc ::clay::is_null value { return [expr {$value in {{} NULL}}] } proc ::clay::leaf args { set marker [string index [lindex $args end] end] set result [path {*}${args}] if {$marker eq "/"} { return $result } return [list {*}[lrange $result 0 end-1] [string trim [string trim [lindex $result end]] /]] } proc ::clay::path args { set result {} foreach item $args { set item [string trim $item :./] foreach subitem [split $item /] { lappend result [string trim ${subitem}]/ } } return $result } proc ::clay::script_path {} { set path [file dirname [file join [pwd] [info script]]] return $path } proc ::clay::NSNormalize qualname { if {![string match ::* $qualname]} { set qualname ::clay::classes::$qualname } regsub -all {::+} $qualname "::" } proc ::clay::uuid_generate args { return [uuid::uuid generate] } namespace eval ::clay { variable option_class {} variable core_classes {::oo::class ::oo::object} } |
Added modules/clay/build/test.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 | ### # Test script build functions ### set result {} putb result {# clay.test - Copyright (c) 2018 Sean Woods # ------------------------------------------------------------------------- #source [file join \ # [file dirname [file dirname [file dirname [file join [pwd] [info script]]]]] \ # compat devtools testutilities.tcl] source [file join [file dirname [file dirname [file join [pwd] [info script]]]] devtools testutilities.tcl] testsNeedTcl 8.6 testsNeedTcltest 2 testsNeed TclOO 1 support { use uuid/uuid.tcl uuid use oodialect/oodialect.tcl oo::dialect } testing { useLocal clay.tcl clay } } putb result { set ::clay::trace 0 } putb result { # ------------------------------------------------------------------------- # dictmerge Testing unset -nocomplain foo test dictmerge-0001 {Invoking dictmerge with empty args on a non existent variable create an empty variable} { ::clay::dictmerge foo set foo } {} unset -nocomplain foo ::clay::dictmerge foo bar/ baz/ bell/ bang test dictmerge-0002 {For new entries dictmerge is essentially a set} { dict get $foo bar/ baz/ bell/ } {bang} ::clay::dictmerge foo bar/ baz/ boom/ bang test dictmerge-0003 {For entries that do exist a zipper merge is performed} { dict get $foo bar/ baz/ bell/ } {bang} test dictmerge-0004 {For entries that do exist a zipper merge is performed} { dict get $foo bar/ baz/ boom/ } {bang} ::clay::dictmerge foo bar/ baz/ bop {color green flavor strawberry} test dictmerge-0005 {Leaves are replaced even if they look like a dict} { dict get $foo bar/ baz/ bop } {color green flavor strawberry} ::clay::dictmerge foo bar/ baz/ bop {color yellow} test dictmerge-0006 {Leaves are replaced even if they look like a dict} { dict get $foo bar/ baz/ bop } {color yellow} ::clay::dictmerge foo bar/ baz/ bang/ {color green flavor strawberry} test dictmerge-0005 {Branches are merged} { dict get $foo bar/ baz/ bang/ } {color green flavor strawberry} ::clay::dictmerge foo bar/ baz/ bang/ color yellow test dictmerge-0006 {Branches are merged} { dict get $foo bar/ baz/ bang/ } {color yellow flavor strawberry} ::clay::dictmerge foo bar/ baz/ bang/ {color blue} test dictmerge-0007 {Branches are merged} { dict get $foo bar/ baz/ bang/ } {color blue flavor strawberry} ::clay::dictmerge foo {option/ {color {type color} flavor {sense taste}}} ::clay::dictmerge foo {option/ {format {default ascii}}} test dictmerge-0008 {Whole dicts are merged} { dict get $foo option/ color } {type color} test dictmerge-0009 {Whole dicts are merged} { dict get $foo option/ flavor } {sense taste} test dictmerge-0010 {Whole dicts are merged} { dict get $foo option/ format } {default ascii} ### # Tests for the httpd module ### test dictmerge-0010 {Test that leaves are merged properly} set bar {} ::clay::dictmerge bar { proxy/ {port 10101 host myhost.localhost} } ::clay::dictmerge bar { mimetxt {Host: localhost Content_Type: text/plain Content-Length: 15 } http {HTTP_HOST {} CONTENT_LENGTH 15 HOST localhost CONTENT_TYPE text/plain UUID 3a7b4cdc-28d7-49b7-b18d-9d7d18382b9e REMOTE_ADDR 127.0.0.1 REMOTE_HOST 127.0.0.1 REQUEST_METHOD POST REQUEST_URI /echo REQUEST_PATH echo REQUEST_VERSION 1.0 DOCUMENT_ROOT {} QUERY_STRING {} REQUEST_RAW {POST /echo HTTP/1.0} SERVER_PORT 10001 SERVER_NAME 127.0.0.1 SERVER_PROTOCOL HTTP/1.1 SERVER_SOFTWARE {TclHttpd 4.2.0} LOCALHOST 0} UUID 3a7b4cdc-28d7-49b7-b18d-9d7d18382b9e uriinfo {fragment {} port {} path echo scheme http host {} query {} pbare 0 pwd {} user {}} mixin {reply ::test::content.echo} prefix /echo proxy_port 10010 proxy/ {host localhost} } test dictmerge-0011 {Whole dicts are merged} { dict get $bar proxy_port } {10010} test dictmerge-0012 {Whole dicts are merged} { dict get $bar http CONTENT_LENGTH } 15 test dictmerge-0013 {Whole dicts are merged} { dict get $bar proxy/ host } localhost test dictmerge-0014 {Whole dicts are merged} { dict get $bar proxy/ port } 10101 } putb result { # ------------------------------------------------------------------------- ::oo::dialect::create ::alpha proc ::alpha::define::is_alpha {} { dict set ::testinfo([current_class]) is_alpha 1 } ::alpha::define ::alpha::object { is_alpha } ::oo::dialect::create ::bravo ::alpha proc ::bravo::define::is_bravo {} { dict set ::testinfo([current_class]) is_bravo 1 } ::bravo::define ::bravo::object { is_bravo } ::oo::dialect::create ::charlie ::bravo proc ::charlie::define::is_charlie {} { dict set ::testinfo([current_class]) is_charlie 1 } ::charlie::define ::charlie::object { is_charlie } ::oo::dialect::create ::delta ::charlie proc ::delta::define::is_delta {} { dict set ::testinfo([current_class]) is_delta 1 } ::delta::define ::delta::object { is_delta } ::delta::class create adam { is_alpha is_bravo is_charlie is_delta } test oodialect-keyword-001 {Testing keyword application} { set ::testinfo(::adam) } {is_alpha 1 is_bravo 1 is_charlie 1 is_delta 1} test oodialect-keyword-002 {Testing keyword application} { set ::testinfo(::alpha::object) } {is_alpha 1} test oodialect-keyword-003 {Testing keyword application} { set ::testinfo(::bravo::object) } {is_bravo 1} test oodialect-keyword-004 {Testing keyword application} { set ::testinfo(::charlie::object) } {is_charlie 1} test oodialect-keyword-005 {Testing keyword application} { set ::testinfo(::delta::object) } {is_delta 1} ### # Declare an object from a namespace ### namespace eval ::test1 { ::alpha::class create a { aliases A is_alpha } ::alpha::define b { aliases B BEE is_alpha } ::alpha::class create ::c { aliases C is_alpha } ::alpha::define ::d { aliases D is_alpha } } test oodialect-naming-001 {Testing keyword application} { set ::testinfo(::test1::a) } {is_alpha 1} test oodialect-naming-002 {Testing keyword application} { set ::testinfo(::test1::b) } {is_alpha 1} test oodialect-naming-003 {Testing keyword application} { set ::testinfo(::c) } {is_alpha 1} test oodialect-naming-004 {Testing keyword application} { set ::testinfo(::d) } {is_alpha 1} test oodialect-aliasing-001 {Testing keyword application} { namespace eval ::test1 { ::alpha::define e { superclass A } } } ::test1::e test oodialect-aliasing-002 {Testing keyword application} { namespace eval ::test1 { ::bravo::define f { superclass A } } } ::test1::f test oodialect-aliasing-003 {Testing aliase method on class} { ::test1::a aliases } {::test1::A} test oodialect-ancestry-003 {Testing heritage} { ::clay::ancestors ::test1::f } {::test1::f ::test1::a ::bravo::object ::alpha::object ::oo::object} test oodialect-ancestry-004 {Testing heritage} { ::clay::ancestors ::alpha::object } {::alpha::object ::oo::object} test oodialect-ancestry-005 {Testing heritage} { ::clay::ancestors ::delta::object } {::delta::object ::charlie::object ::bravo::object ::alpha::object ::oo::object} # ------------------------------------------------------------------------- # clay submodule testing # ------------------------------------------------------------------------- # Test canonical path building set path {const/ foo/ bar/ baz/} } set testnum 0 foreach {pattern} { {const foo bar baz} {const/ foo/ bar/ baz} {const/foo/bar/baz} {const/foo bar/baz} {const/foo/bar baz} {const foo/bar/baz} {const foo bar/baz} {const/foo bar baz} } { putb result [list %pattern% $pattern %testnum% [format %04d [incr testnum]]] { test oo-clay-path-%testnum% "Test path: %pattern%" { ::clay::path %pattern% } $path } } putb result {set path {const/ foo/ bar/ baz/ bing}} set testnum 0 foreach {pattern} { {const foo bar baz bing} {const/ foo/ bar/ baz/ bing} {const/foo/bar/baz/bing} {const/foo bar/baz/bing:} {const/foo/bar baz bing} {const/foo/bar baz bing:} {const foo/bar/baz/bing} {const foo bar/baz/bing} {const/foo bar baz bing} } { putb result [list %pattern% $pattern %testnum% [format %04d [incr testnum]]] { test oo-clay-leaf-%testnum% "Test leaf: %pattern%" { ::clay::leaf %pattern% } $path } } putb result {namespace eval ::foo {}} set class-a ::foo::classa set commands-a { clay set const color blue clay set const/flavor strawberry clay set {const/ sound} zoink clay set info/ { animal no building no subelement {pedantic yes} } } set claydict-a { const/ {color blue flavor strawberry sound zoink} info/ { animal no building no subelement {pedantic yes} } } putb result [list %class% ${class-a} %commands% ${commands-a}] { clay::define %class% { %commands% } } set testnum 0 foreach {top children} ${claydict-a} { foreach {child value} $children { set map {} dict set map %class% ${class-a} dict set map %top% $top dict set map %child% $child dict set map %value% $value dict set map %testnum% [format %04d [incr testnum]] putb result $map { test oo-class-clay-method-%testnum% "Test %class% %top% %child% exists" { %class% clay exists %top% %child% } 1 } dict set map %test% [format %04d [incr testnum]] putb result $map { test oo-class-clay-method-%testnum% "Test %class% %top% %child% value" { %class% clay get %top% %child% } {%value%} } } } set class-b ::foo::classb set claydict-b { const/ {color black flavor vanilla feeling dread} info/ {subelement {spoon yes}} } set commands-b {} foreach {top children} ${claydict-b} { foreach {child value} $children { putb commands-b " [list clay set $top $child $value]" } } putb result [list %class% ${class-b} %commands% ${commands-b}] { clay::define %class% { %commands% } } foreach {top children} ${claydict-b} { foreach {child value} $children { set map {} dict set map %class% ${class-b} dict set map %top% $top dict set map %child% $child dict set map %value% $value dict set map %testnum% [format %04d [incr testnum]] putb result $map { test oo-class-clay-method-%testnum% "Test %class% %top% %child% exists" { %class% clay exists %top% %child% } 1 } dict set map %test% [format %04d [incr testnum]] putb result $map { test oo-class-clay-method-%testnum% "Test %class% %top% %child% value" { %class% clay get %top% %child% } {%value%} } } } set commands-c {superclass ::foo::classb ::foo::classa} set class-c ::foo::class.ab putb result [list %class% ${class-c} %commands% ${commands-c}] { clay::define %class% { %commands% } } set commands-d {superclass ::foo::classa ::foo::classb} set class-d ::foo::class.ba putb result [list %class% ${class-d} %commands% ${commands-d}] { clay::define %class% { %commands% } } ### # Tests for objects ### putb result {# ------------------------------------------------------------------------- # OBJECT of ::foo::classa set OBJECTA [::foo::classa new] ### # Test object degation ### proc ::foo::fakeobject {a b} { return [expr {$a + $b}] } ::clay::object create TEST TEST clay delegate funct ::foo::fakeobject test oo-object-delegate-001 {Test object delegation} { ::TEST clay delegate } {<class> ::clay::object <funct> ::foo::fakeobject} test oo-object-delegate-002 {Test object delegation} { ::TEST clay delegate funct } {::foo::fakeobject} test oo-object-delegate-002a {Test object delegation} { ::TEST clay delegate <funct> } {::foo::fakeobject} test oo-object-delegate-003 {Test object delegation} { ::TEST <funct> 1 1 } {2} test oo-object-delegate-004 {Test object delegation} { ::TEST <funct> 10 -7 } {3} # Replace the function out from under proc ::foo::fakeobject {a b} { return [expr {$a * $b}] } test oo-object-delegate-005 {Test object delegation} { ::TEST <funct> 10 -7 } {-70} # Object with ::foo::classa mixed in set MIXINA [::oo::object new] oo::objdefine $MIXINA mixin ::foo::classa } set matrix ${claydict-a} set testnum 0 foreach {top children} $matrix { foreach {child value} $children { set map {} dict set map %object1% OBJECTA dict set map %object2% MIXINA dict set map %top% $top dict set map %child% $child dict set map %value% $value dict set map %testnum% [format %04d [incr testnum]] putb result $map { test oo-object-clay-method-native-%testnum% {Test native object gets the property} { $%object1% clay get %top% %child% } {%value%} test oo-object-clay-method-mixin-%testnum% {Test mixin object gets the property} { $%object2% clay get %top% %child% } {%value%} } } } putb result {# ------------------------------------------------------------------------- # OBJECT of ::foo::classb set OBJECTB [::foo::classb new] # Object with ::foo::classb mixed in set MIXINB [::oo::object new] oo::objdefine $MIXINB mixin ::foo::classb } set matrix ${claydict-b} #set testnum 0 foreach {top children} $matrix { foreach {child value} $children { set map {} dict set map %object1% OBJECTB dict set map %object2% MIXINB dict set map %top% $top dict set map %child% $child dict set map %value% $value dict set map %testnum% [format %04d [incr testnum]] putb result $map { test oo-object-clay-method-native-%testnum% {Test native object gets the property} { $%object1% clay get %top% %child% } {%value%} test oo-object-clay-method-mixin-%testnum% {Test mixin object gets the property} { $%object2% clay get %top% %child% } {%value%} } } } putb result {# ------------------------------------------------------------------------- # OBJECT descended from ::foo::classa ::foo::classb set OBJECTAB [::foo::class.ab new] # Object where classes were mixed in ::foo::classa ::foo::classb set MIXINAB [::oo::object new] oo::objdefine $MIXINAB mixin ::foo::classa ::foo::classb } set matrix ${claydict-b} foreach {top children} ${claydict-a} { foreach {child value} $children { if {![dict exists $matrix $top $child]} { dict set matrix $top $child $value } } } #set testnum 0 foreach {top children} $matrix { foreach {child value} $children { set map {} dict set map %object1% OBJECTAB dict set map %object2% MIXINAB dict set map %top% $top dict set map %child% $child dict set map %value% $value dict set map %testnum% [format %04d [incr testnum]] putb result $map { test oo-object-clay-method-native-%testnum% {Test native object gets the property} { $%object1% clay get %top% %child% } {%value%} test oo-object-clay-method-mixin-%testnum% {Test mixin object gets the property} { $%object2% clay get %top% %child% } {%value%} } } } putb result {# ------------------------------------------------------------------------- # OBJECT descended from ::foo::classb ::foo::classa set OBJECTBA [::foo::class.ba new] # Object where classes were mixed in ::foo::classb ::foo::classa set MIXINBA [::oo::object new] oo::objdefine $MIXINBA mixin ::foo::classb ::foo::classa } set matrix ${claydict-a} foreach {top children} ${claydict-b} { foreach {child value} $children { if {![dict exists $matrix $top $child]} { dict set matrix $top $child $value } } } #set testnum 0 foreach {top children} $matrix { foreach {child value} $children { set map {} dict set map %object1% OBJECTBA dict set map %object2% MIXINBA dict set map %top% $top dict set map %child% $child dict set map %value% $value dict set map %testnum% [format %04d [incr testnum]] putb result $map { test oo-object-clay-method-native-%testnum% {Test native object gets the property} { $%object1% clay get %top% %child% } {%value%} test oo-object-clay-method-mixin-%testnum% {Test mixin object gets the property} { $%object2% clay get %top% %child% } {%value%} } } } putb resut { ### # Test local setting if clay data in an object ### set OBJECT [::foo::classa new] test oo-object-clay-method-local-0001 {Test native object gets the property} { $OBJECT clay get const/ color } {blue} test oo-object-clay-method-local-0002 {Test that local settings override the inherited properties} { $OBJECT clay set const/ color black $OBJECT clay set const/ } {black} test oo-object-clay-method-local-0003 {Test native object gets an empty property} { $OBJECT clay get color } {} test oo-object-clay-method-local-0004 {Test that local settings override the empty property} { $OBJECT clay set color orange $OBJECT clay get color } {orange} } putb result { ### # put a do-nothing constructor on the books ### ::clay::define ::clay::object { constructor args {} } oo::objdefine ::clay::object method foo args { return bar } test clay-core-method-0001 {Test that adding methods to the core ::clay::object class works} { ::clay::object foo } {bar} namespace eval ::TEST {} ::clay::define ::TEST::myclass { clay color red clay flavor strawberry } ### # Test adding a clay property ### test clay-class-clay-0001 {Test that a clay statement is recorded in the object of the class} { ::TEST::myclass clay get color } red test clay-class-clay-0002 {Test that a clay statement is recorded in the object of the class} { ::TEST::myclass clay get flavor } strawberry ### # Test that objects of the class get the same properties ### set OBJ [::clay::object new {}] set OBJ2 [::TEST::myclass new {}] test clay-object-clay-a-0001 {Test that objects not thee class do not get properties} { $OBJ clay get color } {} test clay-object-clay-a-0002 {Test that objects not thee class do not get properties} { $OBJ clay get flavor } {} test clay-object-clay-a-0003 {Test that objects of the class get properties} { $OBJ2 clay get color } red test clay-object-clay-a-0004 {Test that objects of the class get properties} { $OBJ2 clay get flavor } strawberry test clay-object-clay-a-0005 {Test the clay ancestors function} { $OBJ clay ancestors } {::clay::object ::oo::object} test clay-object-clay-a-0006 {Test the clay ancestors function} { $OBJ2 clay ancestors } {::TEST::myclass ::clay::object ::oo::object} test clay-object-clay-a-0007 {Test the clay provenance function} { $OBJ2 clay provenance flavor } ::TEST::myclass ### # Test that object local setting override the class ### test clay-object-clay-a-0008 {Test that object local setting override the class} { $OBJ2 clay set color purple $OBJ2 clay get color } purple test clay-object-clay-a-0009 {Test that object local setting override the class} { $OBJ2 clay provenance color } self ::clay::define ::TEST::myclasse { superclass ::TEST::myclass clay color blue method do args { return "I did $args" } Ensemble which::color {} { return [my clay get color] } } ### # Test clay information is passed town to subclasses ### test clay-class-clay-0003 {Test that a clay statement is recorded in the object of the class} { ::TEST::myclasse clay get color } blue test clay-class-clay-0004 {Test that clay statements from the ancestors of this class are not present (we handle them seperately in objects)} { ::TEST::myclasse clay get flavor } {strawberry} ### # Test that properties reach objects ### set OBJ3 [::TEST::myclasse new {}] test clay-object-clay-b-0001 {Test that objects of the class get properties} { $OBJ3 clay get color } blue test clay-object-clay-b-0002 {Test the clay provenance function} { $OBJ3 clay provenance color } ::TEST::myclasse test clay-object-clay-b-0003 {Test that objects of the class get properties} { $OBJ3 clay get flavor } strawberry test clay-object-clay-b-0004 {Test the clay provenance function} { $OBJ3 clay provenance flavor } ::TEST::myclass test clay-object-clay-b-0005 {Test the clay provenance function} { $OBJ3 clay ancestors } {::TEST::myclasse ::TEST::myclass ::clay::object ::oo::object} ### # Test defining a standard method ### test clay-object-method-0001 {Test and standard method} { $OBJ3 do this really cool thing } {I did this really cool thing} test clay-object-method-0003 {Test an ensemble} { $OBJ3 which color } blue # Test setting properties test clay-object-method-0004 {Test an ensemble} { $OBJ3 clay set color black $OBJ3 which color } black ### # Test that if you try to replace a global command you get an error ### test clay-nspace-0001 {Test that if you try to replace a global command you get an error} -body { ::clay::define open { method bar {} { return foo } } } -returnCodes {error} -result "::open does not refer to an object" ::clay::define fubar { method bar {} { return foo } } test clay-nspace-0002 {Test a non qualified class ends up in the current namespace} { info commands ::fubar } {::fubar} namespace eval ::cluster { ::clay::define fubar { method bar {} { return foo } } ::clay::define ::clay::pot { method bar {} { return foo } } } test clay-nspace-0003 {Test a non qualified class ends up in the current namespace} { info commands ::cluster::fubar } {::cluster::fubar} test clay-nspace-0003 {Test a fully qualified class ends up in the proper namespace} { info commands ::clay::pot } {::clay::pot} #set ::clay::trace 3 ### # Mixin tests ### ### # Define a core class ### ::clay::define ::TEST::thing { method do args { return "I did $args" } } ::clay::define ::TEST::vegetable { clay color unknown clay flavor unknown Ensemble which::flavor {} { return [my clay get flavor] } Ensemble which::color {} { return [my clay get color] } } ::clay::define ::TEST::animal { clay color unknown clay sound unknown Ensemble which::sound {} { return [my clay get sound] } Ensemble which::color {} { return [my clay get color] } } ::clay::define ::TEST::species.cat { superclass ::TEST::animal clay sound meow } ::clay::define ::TEST::coloring.calico { clay color calico } ::clay::define ::TEST::condition.dark { Ensemble which::color {} { return grey } } ::clay::define ::TEST::mood.happy { Ensemble which::sound {} { return purr } } test clay-object-0001 {Test than an object is created when clay::define is invoked} { info commands ::TEST::mood.happy } ::TEST::mood.happy set OBJ [::TEST::thing new] test clay-mixin-a-0001 {Test that prior to a mixin an ensemble doesn't exist} -body { $OBJ which color } -returnCodes error -result {unknown method "which": must be clay, destroy or do} test clay-mixin-a-0002 {Test and standard method from an ancestor} { $OBJ do this really cool thing } {I did this really cool thing} $OBJ clay mixinmap species ::TEST::animal test clay-mixin-b-0001 {Test that an ensemble is created during a mixin} { $OBJ which color } {unknown} test clay-mixin-b-0002 {Test that an ensemble is created during a mixin} { $OBJ which sound } {unknown} test clay-mixin-b-0003 {Test that an ensemble is created during a mixin} \ -body {$OBJ which flavor} -returnCodes {error} \ -result {unknown method which flavor. Valid: color sound} test clay-mixin-b-0004 {Test that mixins resolve in the correct order} { $OBJ clay ancestors } {::TEST::animal ::TEST::thing ::clay::object ::oo::object} ### # Replacing a mixin replaces the behaviors ### $OBJ clay mixinmap species ::TEST::vegetable test clay-mixin-c-0001 {Test that an ensemble is created during a mixin} { $OBJ which color } {unknown} test clay-mixin-c-0002 {Test that an ensemble is created during a mixin} \ -body {$OBJ which sound} \ -returnCodes {error} \ -result {unknown method which sound. Valid: color flavor} test clay-mixin-c-0003 {Test that an ensemble is created during a mixin} { $OBJ which flavor } {unknown} test clay-mixin-c-0004 {Test that mixins resolve in the correct order} { $OBJ clay ancestors } {::TEST::vegetable ::TEST::thing ::clay::object ::oo::object} ### # Replacing a mixin $OBJ clay mixinmap species ::TEST::species.cat test clay-mixin-e-0001 {Test that an ensemble is created during a mixin} { $OBJ which color } {unknown} test clay-mixin-e-0002 {Test that an ensemble is created during a mixin} { $OBJ which sound } {meow} test clay-mixin-e-0003 {Test that an ensemble is created during a mixin} \ -body {$OBJ which flavor} -returnCodes {error} \ -result {unknown method which flavor. Valid: color sound} test clay-mixin-e-0004 {Test that clay data follows the rules of inheritence and order of mixin} { $OBJ clay ancestors } {::TEST::species.cat ::TEST::thing ::TEST::animal ::clay::object ::oo::object} $OBJ clay mixinmap coloring ::TEST::coloring.calico test clay-mixin-f-0001 {Test that an ensemble is created during a mixin} { $OBJ which color } {calico} test clay-mixin-f-0002 {Test that an ensemble is created during a mixin} { $OBJ which sound } {meow} test clay-mixin-f-0003 {Test that an ensemble is created during a mixin} \ -body {$OBJ which flavor} -returnCodes {error} \ -result {unknown method which flavor. Valid: color sound} test clay-mixin-f-0004 {Test that clay data follows the rules of inheritence and order of mixin} { $OBJ clay ancestors } {::TEST::coloring.calico ::TEST::species.cat ::TEST::thing ::clay::object ::TEST::animal ::oo::object} test clay-mixin-f-0005 {Test that clay data from a mixin works} { $OBJ clay provenance color } {::TEST::coloring.calico} ### # Test variable initialization ### ::clay::define ::TEST::has_var { Variable my_variable 10 method get_my_variable {} { my variable my_variable return $my_variable } } set OBJ [::TEST::has_var new] test clay-class-variable-0001 {Test that the parser injected the right value in the right place for clay to catch it} { $OBJ clay get variable/ my_variable } {10} test clay-class-variable-0002 {Test that variables declared in the class definition are initialized} { $OBJ get_my_variable } 10 ### # Test array initialization ### ::clay::define ::TEST::has_array { Array my_array {timeout 10} method get_my_array {field} { my variable my_array return $my_array($field) } } set OBJ [::TEST::has_array new] test clay-class-array-0001 {Test that the parser injected the right value in the right place for clay to catch it} { $OBJ clay get array/ } {my_array/ {timeout 10}} test clay-class-arrau-0002 {Test that variables declared in the class definition are initialized} { $OBJ get_my_array timeout } 10 ### # Test dict initialization ### ::clay::define ::TEST::has_dict { Dict my_dict {timeout 10} method get_my_dict {args} { my variable my_dict return [dict get $my_dict {*}$args] } } set OBJ [::TEST::has_dict new] test clay-class-dict-0001 {Test that the parser injected the right value in the right place for clay to catch it} { $OBJ clay get dict/ } {my_dict/ {timeout 10}} test clay-class-dict-0002 {Test that variables declared in the class definition are initialized} { $OBJ get_my_dict timeout } 10 ### # Test object delegation ### ::clay::define ::TEST::organelle { method add args { set total 0 foreach item $args { set total [expr {$total+$item}] } return $total } } ::clay::define ::TEST::master { constructor {} { set mysub [namespace current]::sub ::TEST::organelle create $mysub my clay delegate sub $mysub } } set OBJ [::TEST::master new] ### # Test that delegation is working ### test clay-delegation-0001 {Test an array driven ensemble} { $OBJ <sub> add 5 5 } 10 ### # Test the Ensemble keyword ### ::clay::define ::TEST::with_ensemble { Ensemble myensemble {pattern args} { set ensemble [self method] set emap [my clay ensemble_map $ensemble] set mlist [dict keys $emap [string tolower $pattern]] if {[llength $mlist] != 1} { error "Couldn't figure out what to do with $pattern" } set method [lindex $mlist 0] set arglist [dict get $emap $method arglist] set body [dict get $emap $method body] if {$arglist ni {args {}}} { ::clay::dynamic_arguments $ensemble $method [list $arglist] {*}$args } eval $body } Ensemble myensemble::go args { return 1 } } ::clay::define ::TEST::with_ensemble.dance { Ensemble myensemble::dance args { return 1 } } ::clay::define ::TEST::with_ensemble.cannot_dance { Ensemble myensemble::dance args { return 0 } } set OBJA [::clay::object new] set OBJB [::clay::object new] $OBJA clay mixinmap \ core ::TEST::with_ensemble \ friends ::TEST::with_ensemble.dance $OBJB clay mixinmap \ core ::TEST::with_ensemble \ friends ::TEST::with_ensemble.cannot_dance } set testnum 0 set matrix { go { OBJA 1 OBJB 1 } dance { OBJA 1 OBJB 0 } } foreach {action output} $matrix { putb result "# Test $action" foreach {object value} $output { set map [dict create %object% $object %action% $action %value% $value] dict set map %testnum% [format %04d [incr testnum]] putb result $map {test clay-dynamic-ensemble-%testnum% {Test ensemble with static method} { $%object% myensemble %action% } {%value%}} } } putb result { ### # Class method testing ### clay::class create WidgetClass { class_method working {} { return {Works} } class_method unknown args { set tkpath [lindex $args 0] if {[string index $tkpath 0] eq "."} { set obj [my new $tkpath {*}[lrange $args 1 end]] $obj tkalias $tkpath return $tkpath } next {*}$args } constructor {TkPath args} { my variable hull set hull $TkPath my clay delegate hull $TkPath } method tkalias tkname { set oldname $tkname my variable tkalias set tkalias $tkname set self [self] set hullwidget [::info object namespace $self]::tkwidget my clay delegate tkwidget $hullwidget #rename ::$tkalias $hullwidget my clay delegate hullwidget $hullwidget #::tool::object_rename [self] ::$tkalias rename [self] ::$tkalias #my Hull_Bind $tkname return $hullwidget } } test tool-class-method-000 {Test that class methods actually work...} { WidgetClass working } {Works} test tool-class-method-001 {Test Tk style creator} { WidgetClass .foo .foo clay delegate hull } {.foo} ::clay::define WidgetNewClass { superclass WidgetClass } test tool-class-method-002 {Test Tk style creator inherited by morph} { WidgetNewClass .bar .bar clay delegate hull } {.bar} ### # Test ensemble inheritence ### clay::define NestedClassA { Ensemble do::family {} { return NestedClassA } Ensemble do::something {} { return A } Ensemble do::whop {} { return A } } clay::define NestedClassB { superclass NestedClassA Ensemble do::family {} { set r [next family] lappend r NestedClassB return $r } Ensemble do::whop {} { return B } } clay::define NestedClassC { superclass NestedClassB Ensemble do::somethingelse {} { return C } } clay::define NestedClassD { superclass NestedClassB Ensemble do::somethingelse {} { return D } } clay::define NestedClassE { superclass NestedClassD NestedClassC } clay::define NestedClassF { superclass NestedClassC NestedClassD } NestedClassC create NestedObjectC ### # These tests no longer work because method ensembles are now dynamically # generated by object, that are not attached to the class anymore # #### #test tool-ensemble-001 {Test that an ensemble can access [next] even if no object of the ancestor class have been instantiated} { # NestedObjectC do family #} {::NestedClassA ::NestedClassB ::NestedClassC} test tool-ensemble-002 {Test that a later ensemble definition trumps a more primitive one} { NestedObjectC do whop } {B} test tool-ensemble-003 {Test that an ensemble definitions in an ancestor carry over} { NestedObjectC do something } {A} NestedClassE create NestedObjectE NestedClassF create NestedObjectF test tool-ensemble-004 {Test that ensembles follow the same rules for inheritance as methods} { NestedObjectE do somethingelse } {D} test tool-ensemble-005 {Test that ensembles follow the same rules for inheritance as methods} { NestedObjectF do somethingelse } {C} ### # Set of tests to exercise the mixinmap system ### clay::define MixinMainClass { Variable mainvar unchanged Ensemble test::which {} { my variable mainvar return $mainvar } Ensemble test::main args { puts [list this is main $method $args] } } set mixoutscript {my test untool $class} set mixinscript {my test tool $class} clay::define MixinTool { Variable toolvar unchanged.mixin clay set mixin/ unmap-script $mixoutscript clay set mixin/ map-script $mixinscript clay set mixin/ name {Generic Tool} Ensemble test::untool class { my variable toolvar mainvar set mainvar {} set toolvar {} } Ensemble test::tool class { my variable toolvar mainvar set mainvar [$class clay get mixin/ name] set toolvar [$class clay get mixin/ name] } } clay::define MixinToolA { superclass MixinTool clay set mixin/ name {Tool A} } clay::define MixinToolB { superclass MixinTool clay set mixin/ name {Tool B} method test_newfunc {} { return "B" } } test tool-mixinspec-001 {Test application of mixin specs} { MixinTool clay get mixin/ map-script } $mixinscript test tool-mixinspec-002 {Test application of mixin specs} { MixinToolA clay get mixin/ map-script } $mixinscript test tool-mixinspec-003 {Test application of mixin specs} { MixinToolB clay get mixin/ map-script } $mixinscript MixinMainClass create mixintest test tool-mixinmap-001 {Test object prior to mixins} { mixintest test which } {unchanged} mixintest clay mixinmap tool MixinToolA test tool-mixinmap-002 {Test mixin map script ran} { mixintest test which } {Tool A} mixintest clay mixinmap tool MixinToolB test tool-mixinmap-003 {Test mixin map script ran} { mixintest test which } {Tool B} test tool-mixinmap-003 {Test mixin map script ran} { mixintest test_newfunc } {B} mixintest clay mixinmap tool {} test tool-mixinmap-004 {Test object prior to mixins} { mixintest test which } {} } ### # TESTS NEEDED: # destructor ### putb result { testsuiteCleanup # Local variables: # mode: tcl # indent-tabs-mode: nil # End: } return $result |
Added modules/clay/clay.man.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 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 | [vset VERSION 0.3] [comment {-*- tcl -*- doctools manpage}] [manpage_begin clay n [vset VERSION]] [keywords oo] [copyright {2018 Sean Woods <[email protected]>}] [moddesc {Clay Framework}] [titledesc {A minimalist framework for large scale OO Projects}] [category {Programming tools}] [keywords TclOO] [require Tcl 8.6] [require uuid] [require oo::dialect] [description] Clay introduces a method ensemble to both [class oo::class] and [class oo::object] called clay. This ensemble handles all of the high level interactions within the framework. Clay stores structured data. Clan manages method delegation. Clay has facilities to manage the complex interactions that come about with mixins. [para] The central concept is that inside of every object and class (which are actually objects too) is a dict called clay. What is stored in that dict is left to the imagination. But because this dict is exposed via a public method, we can share structured data between object, classes, and mixins. [para] [subsection {Structured Data}] Clay uses a standardized set of method interactions and introspection that TclOO already provides to perform on-the-fly searches. On-the-fly searches mean that the data is never stale, and we avoid many of the sorts of collisions that would arise when objects start mixing in other classes during operation. [para] The [method clay] methods for both classes and objects have a get and a set method. For objects, get will search through the local clay dict. If the requested leaf is not found, or the query is for a branch, the system will then begin to poll the clay methods of all of the class that implements the object, all of that classes’ ancestors, as well as all of the classes that have been mixed into this object, and all of their ancestors. [para] Intended branches on a tree end with a directory slash (/). Intended leaves are left unadorned. This is a guide for the tool that builds the search results to know what parts of a dict are intended to be branches and which are intended to be leaves. For simple cases, branch marking can be ignored: [example { ::oo::class create ::foo { } ::foo clay set property/ color blue ::foo clay set property/ shape round set A [::foo new] $A clay get property/ {color blue shape round} $A clay set property/ shape square $A clay get property/ {color blue shape square} }] [para] But when you start storing blocks of text, guessing what field is a dict and what isn’t gets messy: [example { ::foo clay set description {A generic thing of designated color and shape} $A clay get description {A generic thing of designated color and shape} Without a convention for discerning branches for leaves what should have been a value can be accidentally parsed as a dictionary, and merged with all of the other values that were never intended to be merge. Here is an example of it all going wrong: ::oo::class create ::foo { } # Add description as a leaf ::foo clay set description \ {A generic thing of designated color and shape} # Add description as a branch ::foo clay set description/ \ {A generic thing of designated color and shape} ::oo::class create ::bar { superclass foo } # Add description as a leaf ::bar clay set description \ {A drinking establishment of designated color and shape and size} # Add description as a branch ::bar clay set description/ \ {A drinking establishment of designated color and shape and size} set B [::bar new] # As a leaf we get the value verbatim from he nearest ancestor $B clay get description {A drinking establishment of designated color and shape and size} # As a branch we get a recursive merge $B clay get description/ {A drinking establishment of designated color and size thing of} }] [subsection {Clay Dialect}] Clay is built using the oo::dialect module from Tcllib. oo::dialect allows you to either add keywords directly to clay, or to create your own metaclass and keyword set using Clay as a foundation. For details on the keywords and what they do, consult the functions in the ::clay::define namespace. [subsection {Method Delegation}] Method Delegation It is sometimes useful to have an external object that can be invoked as if it were a method of the object. Clay provides a delegate ensemble method to perform that delegation, as well as introspect which methods are delegated in that manner. All delegated methods are marked with html-like tag markings (< >) around them. [example { ::clay::define counter { Variable counter 0 method incr {{howmuch 1}} { my variable counter incr counter $howmuch } method value {} { my variable counter return $counter } method reset {} { my variable counter set counter 0 } } ::clay::define example { variable buffer constructor {} { # Build a counter object set obj [namespace current]::counter ::counter create $obj # Delegate the counter my delegate <counter> $obj } method line {text} { my <counter> incr append buffer $text } } set A [example new] $A line {Who’s line is it anyway?} $A <counter> value 1 }] [section {Commands}] [list_begin definitions] [call proc [cmd putb] [opt "[arg map]"] [arg text]] Append a line of text to a variable. Optionally apply a string mapping. [call proc [cmd clay::ancestors] [opt "[arg args]"]] [call proc [cmd clay::args_to_dict] [opt "[arg args]"]] [call proc [cmd clay::args_to_options] [opt "[arg args]"]] [call proc [cmd clay::dictmerge] [arg varname] [opt "[arg args]"]] [call proc [cmd clay::_dictmerge] [arg a] [arg b]] [call proc [cmd clay::dictputb] [arg dict]] [call proc [cmd clay::_dictputb] [arg leaf] [arg level] [arg varname] [arg dict]] [call proc [cmd clay::dynamic_arguments] [arg ensemble] [arg method] [arg arglist] [opt "[arg args]"]] [call proc [cmd clay::dynamic_wrongargs_message] [arg arglist]] [call proc [cmd clay::is_dict] [arg d]] [call proc [cmd clay::is_null] [arg value]] [call proc [cmd clay::leaf] [opt "[arg args]"]] [call proc [cmd clay::path] [opt "[arg args]"]] [call proc [cmd clay::script_path]] [call proc [cmd clay::NSNormalize] [arg qualname]] [call proc [cmd clay::uuid_generate] [opt "[arg args]"]] [call proc [cmd clay::dynamic_methods] [arg class]] [call proc [cmd clay::dynamic_methods_class] [arg thisclass]] [call proc [cmd clay::define::Array] [arg name] [opt "[arg values] [const ""]"]] New OO Keywords for clay [call proc [cmd clay::define::component] [arg name] [arg info]] [call proc [cmd clay::define::constructor] [arg arglist] [arg rawbody]] [call proc [cmd clay::define::class_method] [arg name] [arg arglist] [arg body]] [call proc [cmd clay::define::clay] [opt "[arg args]"]] [call proc [cmd clay::define::destructor] [arg rawbody]] [call proc [cmd clay::define::Dict] [arg name] [opt "[arg values] [const ""]"]] [call proc [cmd clay::define::Variable] [arg name] [opt "[arg default] [const ""]"]] This keyword can also be expressed: [example {property variable NAME {default DEFAULT}}] [para] Variables registered in the variable property are also initialized (if missing) when the object changes class via the [emph morph] method. [call proc [cmd clay::object_create] [arg objname] [opt "[arg class] [const ""]"]] [call proc [cmd clay::object_rename] [arg object] [arg newname]] [call proc [cmd clay::object_destroy] [arg objname]] [call proc [cmd clay::ensemble_methodbody] [arg ensemble] [arg einfo]] [call proc [cmd clay::define::Ensemble] [arg rawmethod] [arg arglist] [arg body]] [call proc [cmd clay::cat] [arg fname]] Concatenate a file [call proc [cmd clay::docstrip] [arg text]] Strip the global comments from tcl code. Used to prevent the documentation markup comments from clogging up files intended for distribution in machine readable format. [list_end] [section Classes] [subsection {Class oo::class}] [para] [class {Methods}] [list_begin definitions] [call method [cmd "clay ancestors"]] Return this class and all ancestors in search order. [call method [cmd "clay dump"]] Return a complete dump of this object's clay data, but only this object's clay data. [call method [cmd "clay get"] [arg path] [opt [option "path..."]]] Pull a chunk of data from the clay system. If the last element of [emph path] is a branch (ends in a slash /), returns a recursive merge of all data from this object and it's constituent classes of the data in that branch. If the last element is a leaf, search this object for a matching leaf, or search all constituent classes for a matching leaf and return the first value found. If no value is found, returns an empty string. [call method [cmd "clay merge"] [arg dict] [opt [option "dict..."]]] Recursively merge the dictionaries given into the object's local clay storage. [call method [cmd "clay replace"] [arg dictionary]] Replace the contents of the internal clay storage with the dictionary given. [call method [cmd "clay search"] [arg path] [opt [option "path..."]]] Return the first matching value for the path in either this class's clay data or one of its ancestors [call method [cmd "clay set"] [arg path] [opt [option "path..."]] [arg value]] Merge the conents of [const value] with the object's clay storage at [const path]. [list_end] [para] [subsection {Class oo::object}] [para] [class {Methods}] [list_begin definitions] [call method [cmd "clay ancestors"]] Return the class this object belongs to, all classes mixed into this object, and all ancestors of those classes in search order. [call method [cmd "clay cget"] [arg field]] Pull a value from either the object's clay structure or one of its constituent classes that matches the field name. The order of search us: [para] 1. The as a value in local dict variable config [para] 2. The as a value in local dict variable clay [para] 3. As a leaf in any ancestor as a root of the clay tree [para] 4. As a leaf in any ancestor under the const/ branch of the clay tree [call method [cmd "clay delegate"] [opt "[arg stub]"] [opt "[arg object]"]] Introspect or control method delegation. With no arguments, the method will return a key/value list of stubs and objects. With just the [arg stub] argument, the method will return the object (if any) attached to the stub. With a [arg stub] and an [arg object] this command will forward all calls to the method [arg stub] to the [arg object]. [call method [cmd "clay dump"]] Return a complete dump of this object's clay data, as well as the data from all constituent classes recursively blended in. [call method [cmd "clay ensemble_map"]] Return a dictionary describing the method ensembles to be assembled for this object [call method [cmd "clay eval"] [arg script]] Evaluated a script in the namespace of this object [call method [cmd "clay evolve"]] Trigger the [method InitializePublic] private method [call method [cmd "clay exists"] [arg path] [opt [option "path..."]]] Returns 1 if [emph path] exists in either the object's clay data. Values greater than one indicate the element exists in one of the object's constituent classes. A value of zero indicates the path could not be found. [call method [cmd "clay flush"]] Wipe any caches built by the clay implementation [call method [cmd "clay forward"] [arg method] [arg object]] A convenience wrapper for [example {oo::objdefine [self] forward {*}$args}] [call method [cmd "clay get"] [arg path] [opt [option "path..."]]] Pull a chunk of data from the clay system. If the last element of [emph path] is a branch (ends in a slash /), returns a recursive merge of all data from this object and it's constituent classes of the data in that branch. If the last element is a leaf, search this object for a matching leaf, or search all constituent classes for a matching leaf and return the first value found. If no value is found, returns an empty string. [call method [cmd "clay leaf"] [arg path] [opt [option "path..."]]] A modified get which is tailored to pull only leaf elements [call method [cmd "clay merge"] [arg dict] [opt [option "dict..."]]] Recursively merge the dictionaries given into the object's local clay storage. [call method [cmd "clay mixin"] [arg class] [opt [option "class..."]]] Perform [lb]oo::objdefine [lb]self[rb] mixin[rb] on this object, with a few additional rules: Prior to the call, for any class was previously mixed in, but not in the new result, execute the script registered to mixin/ unmap-script (if given.) For all new classes, that were not present prior to this call, after the native TclOO mixin is invoked, execute the script registered to mixin/ map-script (if given.) Fall all classes that are now present and “mixed in”, execute the script registered to mixin/ react-script (if given.) [call method [cmd "clay mixinmap"] [opt "[arg stub]"] [opt "[arg classes]"]] With no arguments returns the map of stubs and classes mixed into the current object. When only stub is given, returns the classes mixed in on that stub. When stub and classlist given, replace the classes currently on that stub with the given classes and invoke clay mixin on the new matrix of mixed in classes. [call method [cmd "clay provenance"] [arg path] [opt [option "path..."]]] Return either [const self] if that path exists in the current object, or return the first class (if any) along the clay search path which contains that element. [call method [cmd "clay replace"] [arg dictionary]] Replace the contents of the internal clay storage with the dictionary given. [call method [cmd "clay source"] [arg filename]] Source the given filename within the object's namespace [call method [cmd "clay set"] [arg path] [opt [option "path..."]] [arg value]] Merge the conents of [const value] with the object's clay storage at [const path]. [call method [cmd "InitializePublic"]] Instantiate variables. Called on object creation and during clay mixin. [list_end] [para] [subsection {Class clay::object}] clay::object This class is inherited by all classes that have options. [para] [class {Methods}] [list_begin definitions] [call method [cmd "InitializePublic"]] Instantiate variables and build ensemble methods. [list_end] [para] [subsection {Class clay::doctool}] [example {{ set authors { {John Doe} {[email protected]} {Tom RichardHarry} {[email protected]} } # Create the object ::clay::doctool create AutoDoc set fout [open [file join $moddir module.tcl] w] foreach file [glob [file join $srcdir *.tcl]] { set content [::clay::cat [file join $srcdir $file]] # Scan the file AutoDoc scan_text $content # Strip the comments from the distribution puts $fout [::clay::docstrip $content] } # Write out the manual page set manout [open [file join $moddir module.man] w] dict set arglist header [string map $modmap [::clay::cat [file join $srcdir manual.txt]]] dict set arglist footer [string map $modmap [::clay::cat [file join $srcdir footer.txt]]] dict set arglist authors $authors puts $manout [AutoDoc manpage {*}$arglist] close $manout }}] [para] Tool for build scripts to dynamically generate manual files from comments in source code files [para] [class {Methods}] [list_begin definitions] [call method [cmd "constructor"]] [call method [cmd "arglist"] [arg arglist]] Process an argument list into an informational dict. This method also understands non-positional arguments expressed in the notation of Tip 471 [uri https://core.tcl-lang.org/tips/doc/trunk/tip/479.md]. [para] The output will be a dictionary of all of the fields and whether the fields are [const positional], [const mandatory], and whether they have a [const default] value. [para] [para]Example: [example { my arglist {a b {c 10}} > a {positional 1 mandatory 1} b {positional 1 mandatory 1} c {positional 1 mandatory 0 default 10} }] [call method [cmd "comment"] [arg block]] Convert a block of comments into an informational dictionary. If lines in the comment start with a single word ending in a colon, all subsequent lines are appended to a dictionary field of that name. If no fields are given, all of the text is appended to the [const description] field. [para]Example: [example { my comment {Does something cool} > description {Does something cool} my comment { title : Something really cool author : Sean Woods author : John Doe description : This does something really cool! } > description {This does something really cool!} title {Something really cool} author {Sean Woods John Doe} }] [call method [cmd "keyword.Class"] [arg resultvar] [arg commentblock] [arg name] [arg body]] Process an oo::objdefine call that modifies the class object itself [call method [cmd "keyword.class"] [arg resultvar] [arg commentblock] [arg name] [arg body]] Process an oo::define, clay::define, etc statement. [call method [cmd "keyword.class_method"] [arg resultvar] [arg commentblock] [arg name] [opt "[arg args]"]] Process a statement for a clay style class method [call method [cmd "keyword.method"] [arg resultvar] [arg commentblock] [arg name] [opt "[arg args]"]] Process a statement for a tcloo style object method [call method [cmd "keyword.proc"] [arg commentblock] [arg name] [arg arglist] [arg body]] Process a proc statement [call method [cmd "reset"]] Reset the state of the object and its embedded coroutine [call method [cmd "Main"]] Main body of the embedded coroutine for the object [call method [cmd "section.method"] [arg keyword] [arg method] [arg minfo]] Generate the manual page text for a method or proc [call method [cmd "section.class"] [arg class_name] [arg class_info]] Generate the manual page text for a class [call method [cmd "section.command"] [arg procinfo]] Generate the manual page text for the commands section [call method [cmd "manpage"] [opt "[option "header [emph value]"]"] [opt "[option "footer [emph value]"]"] [opt "[option "authors [emph list]"]"]] Generate the manual page. Returns the completed text suitable for saving in .man file. The header argument is a block of doctools text to go in before the machine generated section. footer is a block of doctools text to go in after the machine generated section. authors is a list of individual authors and emails in the form of AUTHOR EMAIL ?AUTHOR EMAIL?... [call method [cmd "scan_text"] [arg text]] Scan a block of text [call method [cmd "scan_file"] [arg filename]] Scan a file of text [list_end] [para] [section AUTHORS] Sean Woods [uri mailto:<[email protected]>][para] [vset CATEGORY oo] [include ../doctools2base/include/feedback.inc] [manpage_end] |
Added modules/clay/clay.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 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 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 | ### # clay.tcl # # Copyright (c) 2018 Sean Woods # # BSD License ### # @@ Meta Begin # Package clay 0.3 # Meta platform tcl # Meta summary A minimalist framework for complex TclOO development # Meta description This package introduces the method "clay" to both oo::object # Meta description and oo::class which facilitate complex interactions between objects # Meta description and their ancestor and mixed in classes. # Meta category TclOO # Meta subject framework # Meta require {Tcl 8.6} # Meta author Sean Woods # Meta license BSD # @@ Meta End ### # Amalgamated package for clay # Do not edit directly, tweak the source in build/ and rerun # build.tcl ### package provide clay 0.3 namespace eval ::clay {} ### # START: core.tcl ### package require Tcl 8.6 ;# try in pipeline.tcl. Possibly other things. package require TclOO package require uuid package require oo::dialect ::oo::dialect::create ::clay ::namespace eval ::clay {} ::namespace eval ::clay::classes {} ::namespace eval ::clay::define {} ### # END: core.tcl ### ### # START: procs.tcl ### if {[info commands ::ladd] eq {}} { proc ladd {varname args} { upvar 1 $varname var if ![info exists var] { set var {} } foreach item $args { if {$item in $var} continue lappend var $item } return $var } } if {[info command ::ldelete] eq {}} { proc ::ldelete {varname args} { upvar 1 $varname var if ![info exists var] { return } foreach item [lsort -unique $args] { while {[set i [lsearch $var $item]]>=0} { set var [lreplace $var $i $i] } } return $var } } if {[info command ::lrandom] eq {}} { proc ::lrandom list { set len [llength $list] set idx [expr int(rand()*$len)] return [lindex $list $idx] } } if {[::info commands ::tcl::dict::getnull] eq {}} { proc ::tcl::dict::getnull {dictionary args} { if {[exists $dictionary {*}$args]} { get $dictionary {*}$args } } namespace ensemble configure dict -map [dict replace\ [namespace ensemble configure dict -map] getnull ::tcl::dict::getnull] } proc ::putb {buffername args} { upvar 1 $buffername buffer switch [llength $args] { 1 { append buffer [lindex $args 0] \n } 2 { append buffer [string map {*}$args] \n } default { error "usage: putb buffername ?map? string" } } } namespace eval ::clay {} set ::clay::trace 0 proc ::clay::ancestors args { set result {} set queue {} foreach class [lreverse $args] { lappend queue $class } # Rig things such that that the top superclasses # are evaluated first while {[llength $queue]} { set tqueue $queue set queue {} foreach qclass $tqueue { foreach aclass [::info class superclasses $qclass] { if { $aclass in $result } continue if { $aclass in $queue } continue lappend queue $aclass } } foreach item $tqueue { if { $item ni $result } { lappend result $item } } } return $result } proc ::clay::args_to_dict args { if {[llength $args]==1} { return [lindex $args 0] } return $args } proc ::clay::args_to_options args { set result {} foreach {var val} [args_to_dict {*}$args] { lappend result [string trim $var -:] $val } return $result } proc ::clay::dictmerge {varname args} { upvar 1 $varname result if {![info exists result]} { set result {} } switch [llength $args] { 0 { return } 1 { set result [_dictmerge $result [lindex $args 0]] return $result } 2 { lassign $args path value } default { # Merge b into a, and handle nested dicts appropriately set value [lindex $args end] set path [lrange $args 0 end-1] } } if {![dict exists $result {*}$path]} { dict set result {*}$path $value return $result } if {[string index [lindex $path end] end] ne "/"} { dict set result {*}$path $value return $result } ::dict for { k v } $value { # Element names that end in "/" are assumed to be branches if {[string index $k end] eq "/" && [::dict exists $result {*}$path $k]} { # key exists in a and b? let's see if both values are dicts # both are dicts, so merge the dicts set dvalue [::dict get $result {*}$path $k] if { [is_dict $dvalue] && [is_dict $v] } { ::dict set result {*}$path $k [_dictmerge $dvalue $v] } else { ::dict set result {*}$path $k $v } } else { ::dict set result {*}$path $k $v } } return $result } proc ::clay::_dictmerge {a b} { ::set result $a # Merge b into a, and handle nested dicts appropriately ::dict for { k v } $b { if {[string index $k end] ne "/"} { # Element names that do not end in "/" are assumed to be literals # or dict trees we intend to replace wholly ::dict set result $k $v } elseif { [::dict exists $result $k] } { # key exists in a and b? let's see if both values are dicts # both are dicts, so merge the dicts if { [is_dict [::dict get $result $k]] && [is_dict $v] } { ::dict set result $k [_dictmerge [::dict get $result $k] $v] } else { ::dict set result $k $v } } else { ::dict set result $k $v } } return $result } proc ::clay::dictputb {dict} { set result {} set level -1 _dictputb 0 $level result $dict return $result } proc ::clay::_dictputb {leaf level varname dict} { upvar 1 $varname result incr level foreach {field value} $dict { if {[string index $field end] eq "/"} { putb result "[string repeat " " $level]$field \{" _dictputb 0 $level result $value putb result "[string repeat " " $level]\}" } else { putb result "[string repeat " " $level][list $field $value]" } } } proc ::clay::dynamic_arguments {ensemble method arglist args} { set idx 0 set len [llength $args] if {$len > [llength $arglist]} { ### # Catch if the user supplies too many arguments ### set dargs 0 if {[lindex $arglist end] ni {args dictargs}} { return -code error -level 2 "Usage: $ensemble $method [string trim [dynamic_wrongargs_message $arglist]]" } } foreach argdef $arglist { if {$argdef eq "args"} { ### # Perform args processing in the style of tcl ### uplevel 1 [list set args [lrange $args $idx end]] break } if {$argdef eq "dictargs"} { ### # Perform args processing in the style of tcl ### uplevel 1 [list set args [lrange $args $idx end]] ### # Perform args processing in the style of clay ### set dictargs [::clay::args_to_options {*}[lrange $args $idx end]] uplevel 1 [list set dictargs $dictargs] break } if {$idx > $len} { ### # Catch if the user supplies too few arguments ### if {[llength $argdef]==1} { return -code error -level 2 "Usage: $ensemble $method [string trim [dynamic_wrongargs_message $arglist]]" } else { uplevel 1 [list set [lindex $argdef 0] [lindex $argdef 1]] } } else { uplevel 1 [list set [lindex $argdef 0] [lindex $args $idx]] } incr idx } } proc ::clay::dynamic_wrongargs_message {arglist} { set result "" set dargs 0 foreach argdef $arglist { if {$argdef in {args dictargs}} { set dargs 1 break } if {[llength $argdef]==1} { append result " $argdef" } else { append result " ?[lindex $argdef 0]?" } } if { $dargs } { append result " ?option value?..." } return $result } proc ::clay::is_dict { d } { # is it a dict, or can it be treated like one? if {[catch {::dict size $d} err]} { #::set ::errorInfo {} return 0 } return 1 } proc ::clay::is_null value { return [expr {$value in {{} NULL}}] } proc ::clay::leaf args { set marker [string index [lindex $args end] end] set result [path {*}${args}] if {$marker eq "/"} { return $result } return [list {*}[lrange $result 0 end-1] [string trim [string trim [lindex $result end]] /]] } proc ::clay::path args { set result {} foreach item $args { set item [string trim $item :./] foreach subitem [split $item /] { lappend result [string trim ${subitem}]/ } } return $result } proc ::clay::script_path {} { set path [file dirname [file join [pwd] [info script]]] return $path } proc ::clay::NSNormalize qualname { if {![string match ::* $qualname]} { set qualname ::clay::classes::$qualname } regsub -all {::+} $qualname "::" } proc ::clay::uuid_generate args { return [uuid::uuid generate] } namespace eval ::clay { variable option_class {} variable core_classes {::oo::class ::oo::object} } ### # END: procs.tcl ### ### # START: class.tcl ### oo::define oo::class { method clay {submethod args} { my variable clay if {![info exists clay]} { set clay {} } switch $submethod { ancestors { tailcall ::clay::ancestors [self] } exists { set path [::clay::leaf {*}$args] if {![info exists clay]} { return 0 } return [dict exists $clay {*}$path] } dump { return $clay } getnull - get { set path $args set leaf [expr {[string index [lindex $path end] end] ne "/"}] set clayorder [::clay::ancestors [self]] #puts [list [self] clay get {*}$path (leaf: $leaf)] if {$leaf} { #puts [list EXISTS: (clay) [dict exists $clay {*}$path]] if {[dict exists $clay {*}$path]} { return [dict get $clay {*}$path] } #puts [list Search in the in our list of classes for an answer] foreach class $clayorder { if {$class eq [self]} continue if {[$class clay exists {*}$path]} { set value [$class clay get {*}$path] return $value } } } else { set result {} # Leaf searches return one data field at a time # Search in our local dict # Search in the in our list of classes for an answer foreach class [lreverse $clayorder] { if {$class eq [self]} continue ::clay::dictmerge result [$class clay get {*}$path] } if {[dict exists $clay {*}$path]} { ::clay::dictmerge result [dict get $clay {*}$path] } return $result } } merge { foreach arg $args { ::clay::dictmerge clay {*}$arg } } search { foreach aclass [::clay::ancestors [self]] { if {[$aclass clay exists {*}$args]} { return [$aclass clay get {*}$args] } } } set { #puts [list [self] clay SET {*}$args] set value [lindex $args end] set path [::clay::leaf {*}[lrange $args 0 end-1]] ::clay::dictmerge clay {*}$path $value } default { dict $submethod clay {*}$args } } } } ### # END: class.tcl ### ### # START: object.tcl ### oo::define oo::object { method clay {submethod args} { my variable clay claycache clayorder config option_canonical if {![info exists clay]} {set clay {}} if {![info exists claycache]} {set claycache {}} if {![info exists config]} {set config {}} if {![info exists clayorder] || [llength $clayorder]==0} { set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] } switch $submethod { ancestors { return $clayorder } cget { # Leaf searches return one data field at a time # Search in our local dict if {[llength $args]==1} { set field [string trim [lindex $args 0] -:/] if {[info exists option_canonical($field)]} { set field $option_canonical($field) } if {[dict exists $config $field]} { return [dict get $config $field] } } if {[dict exists $clay {*}$args]} { return [dict get $clay {*}$args] } # Search in our local cache if {[dict exists $claycache {*}$args]} { return [dict get $claycache {*}$args] } # Search in the in our list of classes for an answer foreach class $clayorder { if {[$class clay exists {*}$args]} { set value [$class clay get {*}$args] dict set claycache {*}$args $value return $value } if {[$class clay exists const/ {*}$args]} { set value [$class clay get const/ {*}$args] dict set claycache {*}$args $value return $value } } return {} } delegate { if {![dict exists $clay delegate/ <class>]} { dict set clay delegate/ <class> [info object class [self]] } if {[llength $args]==0} { return [dict get $clay delegate/] } if {[llength $args]==1} { set stub <[string trim [lindex $args 0] <>]> if {![dict exists $clay delegate/ $stub]} { return {} } return [dict get $clay delegate/ $stub] } if {([llength $args] % 2)} { error "Usage: delegate OR delegate stub OR delegate stub OBJECT ?stub OBJECT? ..." } foreach {stub object} $args { set stub <[string trim $stub <>]> dict set clay delegate/ $stub $object oo::objdefine [self] forward ${stub} $object oo::objdefine [self] export ${stub} } } dump { # Do a full dump of clay data set result $clay # Search in the in our list of classes for an answer foreach class $clayorder { ::clay::dictmerge result [$class clay dump] } ::clay::dictmerge result $clay return $result } ensemble_map { set ensemble [lindex $args 0] my variable claycache set mensemble [string trim $ensemble :/]/ if {[dict exists $claycache method_ensemble/ $mensemble]} { return [dict get $claycache method_ensemble/ $mensemble] } set emap [my clay get method_ensemble/ $mensemble] dict set claycache method_ensemble/ $mensemble $emap return $emap } eval { set script [lindex $args 0] set buffer {} set thisline {} foreach line [split $script \n] { append thisline $line if {![info complete $thisline]} { append thisline \n continue } set thisline [string trim $thisline] if {[string index $thisline 0] eq "#"} continue if {[string length $thisline]==0} continue if {[lindex $thisline 0] eq "my"} { # Line already calls out "my", accept verbatim append buffer $thisline \n } elseif {[string range $thisline 0 2] eq "::"} { # Fully qualified commands accepted verbatim append buffer $thisline \n } elseif { append buffer "my $thisline" \n } set thisline {} } eval $buffer } evolve - initialize { my InitializePublic } exists { # Leaf searches return one data field at a time # Search in our local dict if {[dict exists $clay {*}$args]} { return 1 } # Search in our local cache if {[dict exists $claycache {*}$args]} { return 2 } set count 2 # Search in the in our list of classes for an answer foreach class $clayorder { incr count if {[$class clay exists {*}$args]} { return $count } } return 0 } flush { set claycache {} set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] } forward { oo::objdefine [self] forward {*}$args } getnull - get { set leaf [expr {[string index [lindex $args end] end] ne "/"}] #puts [list [self] clay get {*}$args (leaf: $leaf)] if {$leaf} { #puts [list EXISTS: (clay) [dict exists $clay {*}$args]] if {[dict exists $clay {*}$args]} { return [dict get $clay {*}$args] } # Search in our local cache #puts [list EXISTS: (claycache) [dict exists $claycache {*}$args]] if {[dict exists $claycache {*}$args]} { return [dict get $claycache {*}$args] } # Search in the in our list of classes for an answer foreach class $clayorder { if {[$class clay exists {*}$args]} { set value [$class clay get {*}$args] dict set claycache {*}$args $value return $value } } } else { set result {} # Leaf searches return one data field at a time # Search in our local dict # Search in the in our list of classes for an answer foreach class [lreverse $clayorder] { ::clay::dictmerge result [$class clay get {*}$args] } if {[dict exists $clay {*}$args]} { ::clay::dictmerge result [dict get $clay {*}$args] } return $result } } leaf { # Leaf searches return one data field at a time # Search in our local dict if {[dict exists $clay {*}$args]} { return [dict get $clay {*}$args] } # Search in our local cache if {[dict exists $claycache {*}$args]} { return [dict get $claycache {*}$args] } # Search in the in our list of classes for an answer foreach class $clayorder { if {[$class clay exists {*}$args]} { set value [$class clay get {*}$args] dict set claycache {*}$args $value return $value } } } merge { foreach arg $args { ::clay::dictmerge clay {*}$arg } } mixin { ### # Mix in the class ### set prior [info object mixins [self]] set newmixin {} foreach item $args { lappend newmixin ::[string trimleft $item :] } set newmap $args foreach class $prior { if {$class ni $newmixin} { set script [$class clay get mixin/ unmap-script] if {[string length $script]} { if {[catch $script err errdat]} { puts stderr "[self] MIXIN ERROR POPPING $class:\n[dict get $errdat -errorinfo]" } } } } ::oo::objdefine [self] mixin {*}$args ### # Build a compsite map of all ensembles defined by the object's current # class as well as all of the classes being mixed in ### my InitializePublic foreach class $newmixin { if {$class ni $prior} { set script [$class clay get mixin/ map-script] if {[string length $script]} { if {[catch $script err errdat]} { puts stderr "[self] MIXIN ERROR PUSHING $class:\n[dict get $errdat -errorinfo]" } } } } foreach class $newmixin { set script [$class clay search mixin/ react-script] if {[string length $script]} { if {[catch $script err errdat]} { puts stderr "[self] MIXIN ERROR PEEKING $class:\n[dict get $errdat -errorinfo]" } break } } } mixinmap { my variable clay if {![dict exists $clay mixin]} { dict set clay mixin {} } if {[llength $args]==0} { return [dict get $clay mixin] } elseif {[llength $args]==1} { return [dict getnull $clay mixin [lindex $args 0]] } else { foreach {slot classes} $args { dict set clay mixin $slot $classes } set claycache {} set classlist {} foreach {item class} [dict get $clay mixin] { if {$class ne {}} { lappend classlist $class } } my clay mixin {*}$classlist } } provenance { if {[dict exists $clay {*}$args]} { return self } foreach class $clayorder { if {[$class clay exists {*}$args]} { return $class } } return {} } replace { set clay [lindex $args 0] } source { source [lindex $args 0] } set { #puts [list [self] clay SET {*}$args] set claycache {} ::clay::dictmerge clay {*}$args } default { dict $submethod clay {*}$args } } } method InitializePublic {} { my variable clayorder clay claycache config option_canonical set claycache {} set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] if {![info exists config]} { set config {} } foreach {var value} [my clay get variable/] { set var [string trim $var :/] if { $var in {clay} } continue my variable $var if {![info exists $var]} { if {$::clay::trace>2} {puts [list initialize variable $var $value]} set $var $value } } foreach {var value} [my clay get dict/] { set var [string trim $var :/] my variable $var if {![info exists $var]} { set $var {} } foreach {f v} $value { if {![dict exists ${var} $f]} { if {$::clay::trace>2} {puts [list initialize dict $var $f $v]} dict set ${var} $f $v } } } foreach {var value} [my clay get dict/] { set var [string trim $var :/] foreach {f v} [my clay get $var/] { if {![dict exists ${var} $f]} { if {$::clay::trace>2} {puts [list initialize dict (from const) $var $f $v]} dict set ${var} $f $v } } } foreach {var value} [my clay get array/] { set var [string trim $var :/] if { $var eq {clay} } continue my variable $var if {![info exists $var]} { array set $var {} } foreach {f v} $value { if {![array exists ${var}($f)]} { if {$::clay::trace>2} {puts [list initialize array $var\($f\) $v]} set ${var}($f) $v } } } foreach {var value} [my clay get array/] { set var [string trim $var :/] foreach {f v} [my clay get $var/] { if {![array exists ${var}($f)]} { if {$::clay::trace>2} {puts [list initialize array (from const) $var\($f\) $v]} set ${var}($f) $v } } } foreach {field info} [my clay get option/] { set field [string trim $field -/:] foreach alias [dict getnull $info aliases] { set option_canonical($alias) $field } if {[dict exists $config $field]} continue set getcmd [dict getnull $info default-command] if {$getcmd ne {}} { set value [{*}[string map [list %field% $field %self% [namespace which my]] $getcmd]] } else { set value [dict getnull $info default] } dict set config $field $value set setcmd [dict getnull $info set-command] if {$setcmd ne {}} { {*}[string map [list %field% [list $field] %value% [list $value] %self% [namespace which my]] $setcmd] } } } } ### # END: object.tcl ### ### # START: metaclass.tcl ### proc ::clay::dynamic_methods class { foreach command [info commands [namespace current]::dynamic_methods_*] { $command $class } } proc ::clay::dynamic_methods_class {thisclass} { set methods {} set mdata [$thisclass clay get class_typemethod/] foreach {method info} $mdata { set method [string trimright $method :/-] if {$method in $methods} continue lappend methods $method set arglist [dict getnull $info arglist] set body [dict getnull $info body] ::oo::objdefine $thisclass method $method $arglist $body } } proc ::clay::define::Array {name {values {}}} { set class [current_class] set name [string trim $name :/]/ if {![$class clay exists array/ $name]} { $class clay set array/ $name {} } foreach {var val} $values { $class clay set array/ $name $var $val } } proc ::clay::define::component {name info} { set class [current_class] foreach {field value} $info { $class clay set component/ [string trim $name :/]/ $field $value } } proc ::clay::define::constructor {arglist rawbody} { set body { my variable DestroyEvent set DestroyEvent 0 ::clay::object_create [self] [info object class [self]] # Initialize public variables and options my InitializePublic } append body $rawbody set class [current_class] ::oo::define $class constructor $arglist $body } proc ::clay::define::class_method {name arglist body} { set class [current_class] $class clay set class_typemethod/ [string trim $name :/] [dict create arglist $arglist body $body] } proc ::clay::define::clay {args} { set class [current_class] if {[lindex $args 0] in "cget set branchset"} { $class clay {*}$args } else { $class clay set {*}$args } } proc ::clay::define::destructor rawbody { set body { # Run the destructor once and only once set self [self] my variable DestroyEvent if {$DestroyEvent} return set DestroyEvent 1 ::clay::object_destroy $self } append body $rawbody ::oo::define [current_class] destructor $body } proc ::clay::define::Dict {name {values {}}} { set class [current_class] set name [string trim $name :/]/ if {![$class clay exists dict/ $name]} { $class clay set dict/ $name {} } foreach {var val} $values { $class clay set dict/ $name $var $val } } proc ::clay::define::Variable {name {default {}}} { set class [current_class] set name [string trimright $name :/] $class clay set variable/ $name $default #::oo::define $class variable $name } proc ::clay::object_create {objname {class {}}} { #if {$::clay::trace>0} { # puts [list $objname CREATE] #} } proc ::clay::object_rename {object newname} { if {$::clay::trace>0} { puts [list $object RENAME -> $newname] } } proc ::clay::object_destroy objname { if {$::clay::trace>0} { puts [list $objname DESTROY] } ::cron::object_destroy $objname } ::clay::define ::clay::object { Variable clay {} Variable claycache {} Variable DestroyEvent 0 method InitializePublic {} { next my variable clayorder clay claycache if {[info exists clay]} { set emap [dict getnull $clay method_ensemble/] } else { set emap {} } foreach class [lreverse $clayorder] { ### # Build a compsite map of all ensembles defined by the object's current # class as well as all of the classes being mixed in ### foreach {mensemble einfo} [$class clay get method_ensemble/] { set ensemble [string trim $mensemble :/] if {$::clay::trace>2} {puts [list Defining $ensemble from $class]} foreach {method info} $einfo { dict set info source $class if {$::clay::trace>2} {puts [list Defining $ensemble -> $method from $class - $info]} dict set emap $ensemble $method $info } } } foreach {ensemble einfo} $emap { #if {[dict exists $einfo _body]} continue set body [::clay::ensemble_methodbody $ensemble $einfo] if {$::clay::trace>2} { set rawbody $body set body {puts [list [self] <object> [self method]]} append body \n $rawbody } oo::objdefine [self] method $ensemble {{method default} args} $body } } } ### # END: metaclass.tcl ### ### # START: ensemble.tcl ### ::namespace eval ::clay::define {} proc ::clay::ensemble_methodbody {ensemble einfo} { set default standard set preamble {} set eswitch {} if {[dict exists $einfo default]} { set emethodinfo [dict get $einfo default] set arglist [dict getnull $emethodinfo arglist] set realbody [dict get $emethodinfo body] if {[llength $arglist]==1 && [lindex $arglist 0] in {{} args arglist}} { set body {} } else { set body "\n ::clay::dynamic_arguments $ensemble \$method [list $arglist] {*}\$args" } append body "\n " [string trim $realbody] " \n" set default $body dict unset einfo default } foreach {msubmethod esubmethodinfo} [lsort -dictionary -stride 2 $einfo] { set submethod [string trim $msubmethod :/-] if {$submethod eq "_body"} continue if {$submethod eq "_preamble"} { set preamble [dict getnull $esubmethodinfo body] continue } set arglist [dict getnull $esubmethodinfo arglist] set realbody [dict getnull $esubmethodinfo body] if {[string length [string trim $realbody]] eq {}} { dict set eswitch $submethod {} } else { if {[llength $arglist]==1 && [lindex $arglist 0] in {{} args arglist}} { set body {} } else { set body "\n ::clay::dynamic_arguments $ensemble \$method [list $arglist] {*}\$args" } append body "\n " [string trim $realbody] " \n" if {$submethod eq "default"} { set default $body } else { dict set eswitch $submethod $body } } } set methodlist [lsort -dictionary [dict keys $eswitch]] if {![dict exists $eswitch <list>]} { dict set eswitch <list> {return $methodlist} } if {$default eq "standard"} { set default "error \"unknown method $ensemble \$method. Valid: \$methodlist\"" } dict set eswitch default $default set mbody {} append mbody $preamble \n append mbody \n [list set methodlist $methodlist] append mbody \n "set code \[catch {switch -- \$method [list $eswitch]} result opts\]" append mbody \n {return -options $opts $result} return $mbody } ::proc ::clay::define::Ensemble {rawmethod arglist body} { set class [current_class] #if {$::clay::trace>2} { # puts [list $class Ensemble $rawmethod $arglist $body] #} set mlist [split $rawmethod "::"] set ensemble [string trim [lindex $mlist 0] :/] set mensemble ${ensemble}/ if {[llength $mlist]==1 || [lindex $mlist 1] in "_body"} { set method _body ### # Simple method, needs no parsing, but we do need to record we have one ### $class clay set method_ensemble/ $mensemble _body [dict create arglist $arglist body $body] if {$::clay::trace>2} { puts [list $class clay set method_ensemble/ $mensemble _body ...] } set method $rawmethod if {$::clay::trace>2} { puts [list $class Ensemble $rawmethod $arglist $body] set rawbody $body set body {puts [list [self] $class [self method]]} append body \n $rawbody } ::oo::define $class method $rawmethod $arglist $body return } set method [join [lrange $mlist 2 end] "::"] $class clay set method_ensemble/ $mensemble [string trim $method :/] [dict create arglist $arglist body $body] if {$::clay::trace>2} { puts [list $class clay set method_ensemble/ $mensemble [string trim $method :/] ...] } } ### # END: ensemble.tcl ### ### # START: doctool.tcl ### namespace eval ::clay {} proc ::clay::cat fname { if {![file exists $fname]} { return } set fin [open $fname r] set data [read $fin] close $fin return $data } proc ::clay::docstrip text { set result {} foreach line [split $text \n] { append thisline $line \n if {![info complete $thisline]} continue set outline $thisline set thisline {} if {[string trim $outline] eq {}} { continue } if {[string index [string trim $outline] 0] eq "#"} continue set cmd [string trim [lindex $outline 0] :] if {$cmd eq "namespace" && [lindex $outline 1] eq "eval"} { append result [list {*}[lrange $outline 0 end-1] [docstrip [lindex $outline end]]] \n continue } if {[string match "*::define" $cmd] && [llength $outline]==3} { append result [list {*}[lrange $outline 0 end-1] [docstrip [lindex $outline end]]] \n continue } if {$cmd eq "oo::class" && [lindex $outline 1] eq "create"} { append result [list {*}[lrange $outline 0 end-1] [docstrip [lindex $outline end]]] \n continue } append result $outline } return $result } proc ::putb {buffername args} { upvar 1 $buffername buffer switch [llength $args] { 1 { append buffer [lindex $args 0] \n } 2 { append buffer [string map {*}$args] \n } default { error "usage: putb buffername ?map? string" } } } oo::class create ::clay::doctool { constructor {} { my reset } method arglist {arglist} { set result [dict create] foreach arg $arglist { set name [lindex $arg 0] dict set result $name positional 1 dict set result $name mandatory 1 if {$name in {args dictargs}} { switch [llength $arg] { 1 { dict set result $name mandatory 0 } 2 { dict for {optname optinfo} [lindex $arg 1] { set optname [string trim $optname -:] dict set result $optname {positional 1 mandatory 0} dict for {f v} $optinfo { dict set result $optname [string trim $f -:] $v } } } default { error "Bad argument" } } } else { switch [llength $arg] { 1 { dict set result $name mandatory 1 } 2 { dict set result $name mandatory 0 dict set result $name default [lindex $arg 1] } default { error "Bad argument" } } } } return $result } method comment block { set count 0 set field description set result [dict create description {}] foreach line [split $block \n] { set sline [string trim $line] set fwidx [string first " " $sline] if {$fwidx < 0} { set firstword [string range $sline 0 end] set restline {} } else { set firstword [string range $sline 0 [expr {$fwidx-1}]] set restline [string range $sline [expr {$fwidx+1}] end] } if {[string index $firstword end] eq ":"} { set field [string tolower [string trim $firstword -:]] switch $field { desc { set field description } } if {[string length $restline]} { dict append result $field "$restline\n" } } else { dict append result $field "$line\n" } } return $result } 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 thisline {} continue } 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 { my keyword.method info $commentblock {*}[lrange $thisline 1 end-1] 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] if {[dict exists $info ensemble]} { dict for {method minfo} [dict get $info ensemble] { dict set result class_method "${name} $method" $minfo } } else { 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] if {[dict exists $info ensemble]} { dict for {method minfo} [dict get $info ensemble] { dict set result method "\"${name} $method\"" $minfo } } else { switch [llength $args] { 1 { set arglist [lindex $args 0] } 0 { set arglist dictargs #set body [lindex $args 0] } default {error "could not interpret method $name {*}$args"} } if {![dict exists $info arglist]} { dict set info arglist [my arglist $arglist] } dict set result method "\"[split [string trim $name :] ::]\"" $info } } method keyword.proc {commentblock name arglist body} { set info [my comment $commentblock] if {![dict exists $info arglist]} { dict set info arglist [my arglist $arglist] } return $info } method reset {} { my variable coro set coro [info object namespace [self]]::coro oo::objdefine [self] forward coro $coro if {[info command $coro] ne {}} { rename $coro {} } coroutine $coro {*}[namespace code {my Main}] } method Main {} { my variable info set info [dict create] yield [info coroutine] set thisline {} set commentblock {} set linec 0 while 1 { set line [yield] append thisline $line \n if {![info complete $thisline]} continue set thisline [string trim $thisline] if {[string index $thisline 0] eq "#"} { append commentblock [string trimleft $thisline #] \n set thisline {} continue } set cmd [string trim [lindex $thisline 0] ":"] switch $cmd { 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" } } tao::define - clay::define - tool::define { lassign $thisline tcmd name body my keyword.class info $commentblock $name $body set commentblock {} } oo::class { lassign $thisline tcmd mthd name body my keyword.class info $commentblock $name $body set commentblock {} } 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.method {keyword method minfo} { set result {} set line "\[call $keyword \[cmd $method\]" if {[dict exists $minfo arglist]} { dict for {argname arginfo} [dict get $minfo arglist] { set positional 1 set mandatory 1 set repeating 0 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 " \[emph [dict get $arginfo type]\]" } else { append line " \[emph value\]" } append line "\"" } append line "\]" if {$mandatory==0} { if {[dict exists $arginfo default]} { append line " \[const \"[dict get $arginfo default]\"\]" } append line "\"\]" } if {$repeating} { append line " \[opt \[option \"$argname...\"\]\]" } } } append line \] putb result $line if {[dict exists $minfo description]} { putb result [dict get $minfo description] } if {[dict exists $minfo example]} { putb result "\[para\]Example: \[example [list [dict get $minfo example]]\]" } 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 example}} continue putb result "\[emph \"$f\"\]: $v" putb result {[para]} } if {[dict exists $class_info example]} { putb result "\[example \{[list [dict get $class_info example]]\}\]" 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 [my section.method classmethod $method $minfo] } 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 [my section.method method $method $minfo] } putb result {[list_end]} putb result {[para]} } return $result } method section.command {procinfo} { set result {} putb result "\[section \{Commands\}\]" putb result {[list_begin definitions]} dict for {method minfo} $procinfo { putb result [my section.method proc $method $minfo] } putb result {[list_end]} return $result } method manpage args { my variable info map set result {} set header {} set footer {} set authors {} dict with args {} putb result $header dict for {sec_type sec_info} $info { switch $sec_type { proc { putb result [my section.command $sec_info] } class { 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] } } } } if {[llength $authors]} { putb result {[section AUTHORS]} foreach {name email} $authors { putb result "$name \[uri mailto:$email\]\[para\]" } } putb result $footer putb result {[manpage_end]} return $result } method scan_text {text} { my variable linecount coro set linecount 0 foreach line [split $text \n] { incr linecount $coro $line } } method scan_file {filename} { my variable linecount coro set fin [open $filename r] set linecount 0 while {[gets $fin line]>=0} { incr linecount $coro $line } close $fin } } ### # END: doctool.tcl ### namespace eval ::clay { namespace export * } |
Added modules/clay/clay.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 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 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 | # clay.test - Copyright (c) 2018 Sean Woods # ------------------------------------------------------------------------- #source [file join # [file dirname [file dirname [file dirname [file join [pwd] [info script]]]]] # compat devtools testutilities.tcl] source [file join [file dirname [file dirname [file join [pwd] [info script]]]] devtools testutilities.tcl] testsNeedTcl 8.6 testsNeedTcltest 2 testsNeed TclOO 1 support { use uuid/uuid.tcl uuid use oodialect/oodialect.tcl oo::dialect } testing { useLocal clay.tcl clay } set ::clay::trace 0 # ------------------------------------------------------------------------- # dictmerge Testing unset -nocomplain foo test dictmerge-0001 {Invoking dictmerge with empty args on a non existent variable create an empty variable} { ::clay::dictmerge foo set foo } {} unset -nocomplain foo ::clay::dictmerge foo bar/ baz/ bell/ bang test dictmerge-0002 {For new entries dictmerge is essentially a set} { dict get $foo bar/ baz/ bell/ } {bang} ::clay::dictmerge foo bar/ baz/ boom/ bang test dictmerge-0003 {For entries that do exist a zipper merge is performed} { dict get $foo bar/ baz/ bell/ } {bang} test dictmerge-0004 {For entries that do exist a zipper merge is performed} { dict get $foo bar/ baz/ boom/ } {bang} ::clay::dictmerge foo bar/ baz/ bop {color green flavor strawberry} test dictmerge-0005 {Leaves are replaced even if they look like a dict} { dict get $foo bar/ baz/ bop } {color green flavor strawberry} ::clay::dictmerge foo bar/ baz/ bop {color yellow} test dictmerge-0006 {Leaves are replaced even if they look like a dict} { dict get $foo bar/ baz/ bop } {color yellow} ::clay::dictmerge foo bar/ baz/ bang/ {color green flavor strawberry} test dictmerge-0005 {Branches are merged} { dict get $foo bar/ baz/ bang/ } {color green flavor strawberry} ::clay::dictmerge foo bar/ baz/ bang/ color yellow test dictmerge-0006 {Branches are merged} { dict get $foo bar/ baz/ bang/ } {color yellow flavor strawberry} ::clay::dictmerge foo bar/ baz/ bang/ {color blue} test dictmerge-0007 {Branches are merged} { dict get $foo bar/ baz/ bang/ } {color blue flavor strawberry} ::clay::dictmerge foo {option/ {color {type color} flavor {sense taste}}} ::clay::dictmerge foo {option/ {format {default ascii}}} test dictmerge-0008 {Whole dicts are merged} { dict get $foo option/ color } {type color} test dictmerge-0009 {Whole dicts are merged} { dict get $foo option/ flavor } {sense taste} test dictmerge-0010 {Whole dicts are merged} { dict get $foo option/ format } {default ascii} ### # Tests for the httpd module ### test dictmerge-0010 {Test that leaves are merged properly} set bar {} ::clay::dictmerge bar { proxy/ {port 10101 host myhost.localhost} } ::clay::dictmerge bar { mimetxt {Host: localhost Content_Type: text/plain Content-Length: 15 } http {HTTP_HOST {} CONTENT_LENGTH 15 HOST localhost CONTENT_TYPE text/plain UUID 3a7b4cdc-28d7-49b7-b18d-9d7d18382b9e REMOTE_ADDR 127.0.0.1 REMOTE_HOST 127.0.0.1 REQUEST_METHOD POST REQUEST_URI /echo REQUEST_PATH echo REQUEST_VERSION 1.0 DOCUMENT_ROOT {} QUERY_STRING {} REQUEST_RAW {POST /echo HTTP/1.0} SERVER_PORT 10001 SERVER_NAME 127.0.0.1 SERVER_PROTOCOL HTTP/1.1 SERVER_SOFTWARE {TclHttpd 4.2.0} LOCALHOST 0} UUID 3a7b4cdc-28d7-49b7-b18d-9d7d18382b9e uriinfo {fragment {} port {} path echo scheme http host {} query {} pbare 0 pwd {} user {}} mixin {reply ::test::content.echo} prefix /echo proxy_port 10010 proxy/ {host localhost} } test dictmerge-0011 {Whole dicts are merged} { dict get $bar proxy_port } {10010} test dictmerge-0012 {Whole dicts are merged} { dict get $bar http CONTENT_LENGTH } 15 test dictmerge-0013 {Whole dicts are merged} { dict get $bar proxy/ host } localhost test dictmerge-0014 {Whole dicts are merged} { dict get $bar proxy/ port } 10101 # ------------------------------------------------------------------------- ::oo::dialect::create ::alpha proc ::alpha::define::is_alpha {} { dict set ::testinfo([current_class]) is_alpha 1 } ::alpha::define ::alpha::object { is_alpha } ::oo::dialect::create ::bravo ::alpha proc ::bravo::define::is_bravo {} { dict set ::testinfo([current_class]) is_bravo 1 } ::bravo::define ::bravo::object { is_bravo } ::oo::dialect::create ::charlie ::bravo proc ::charlie::define::is_charlie {} { dict set ::testinfo([current_class]) is_charlie 1 } ::charlie::define ::charlie::object { is_charlie } ::oo::dialect::create ::delta ::charlie proc ::delta::define::is_delta {} { dict set ::testinfo([current_class]) is_delta 1 } ::delta::define ::delta::object { is_delta } ::delta::class create adam { is_alpha is_bravo is_charlie is_delta } test oodialect-keyword-001 {Testing keyword application} { set ::testinfo(::adam) } {is_alpha 1 is_bravo 1 is_charlie 1 is_delta 1} test oodialect-keyword-002 {Testing keyword application} { set ::testinfo(::alpha::object) } {is_alpha 1} test oodialect-keyword-003 {Testing keyword application} { set ::testinfo(::bravo::object) } {is_bravo 1} test oodialect-keyword-004 {Testing keyword application} { set ::testinfo(::charlie::object) } {is_charlie 1} test oodialect-keyword-005 {Testing keyword application} { set ::testinfo(::delta::object) } {is_delta 1} ### # Declare an object from a namespace ### namespace eval ::test1 { ::alpha::class create a { aliases A is_alpha } ::alpha::define b { aliases B BEE is_alpha } ::alpha::class create ::c { aliases C is_alpha } ::alpha::define ::d { aliases D is_alpha } } test oodialect-naming-001 {Testing keyword application} { set ::testinfo(::test1::a) } {is_alpha 1} test oodialect-naming-002 {Testing keyword application} { set ::testinfo(::test1::b) } {is_alpha 1} test oodialect-naming-003 {Testing keyword application} { set ::testinfo(::c) } {is_alpha 1} test oodialect-naming-004 {Testing keyword application} { set ::testinfo(::d) } {is_alpha 1} test oodialect-aliasing-001 {Testing keyword application} { namespace eval ::test1 { ::alpha::define e { superclass A } } } ::test1::e test oodialect-aliasing-002 {Testing keyword application} { namespace eval ::test1 { ::bravo::define f { superclass A } } } ::test1::f test oodialect-aliasing-003 {Testing aliase method on class} { ::test1::a aliases } {::test1::A} test oodialect-ancestry-003 {Testing heritage} { ::clay::ancestors ::test1::f } {::test1::f ::test1::a ::bravo::object ::alpha::object ::oo::object} test oodialect-ancestry-004 {Testing heritage} { ::clay::ancestors ::alpha::object } {::alpha::object ::oo::object} test oodialect-ancestry-005 {Testing heritage} { ::clay::ancestors ::delta::object } {::delta::object ::charlie::object ::bravo::object ::alpha::object ::oo::object} # ------------------------------------------------------------------------- # clay submodule testing # ------------------------------------------------------------------------- # Test canonical path building set path {const/ foo/ bar/ baz/} test oo-clay-path-0001 "Test path: const foo bar baz" { ::clay::path const foo bar baz } $path test oo-clay-path-0002 "Test path: const/ foo/ bar/ baz" { ::clay::path const/ foo/ bar/ baz } $path test oo-clay-path-0003 "Test path: const/foo/bar/baz" { ::clay::path const/foo/bar/baz } $path test oo-clay-path-0004 "Test path: const/foo bar/baz" { ::clay::path const/foo bar/baz } $path test oo-clay-path-0005 "Test path: const/foo/bar baz" { ::clay::path const/foo/bar baz } $path test oo-clay-path-0006 "Test path: const foo/bar/baz" { ::clay::path const foo/bar/baz } $path test oo-clay-path-0007 "Test path: const foo bar/baz" { ::clay::path const foo bar/baz } $path test oo-clay-path-0008 "Test path: const/foo bar baz" { ::clay::path const/foo bar baz } $path set path {const/ foo/ bar/ baz/ bing} test oo-clay-leaf-0001 "Test leaf: const foo bar baz bing" { ::clay::leaf const foo bar baz bing } $path test oo-clay-leaf-0002 "Test leaf: const/ foo/ bar/ baz/ bing" { ::clay::leaf const/ foo/ bar/ baz/ bing } $path test oo-clay-leaf-0003 "Test leaf: const/foo/bar/baz/bing" { ::clay::leaf const/foo/bar/baz/bing } $path test oo-clay-leaf-0004 "Test leaf: const/foo bar/baz/bing:" { ::clay::leaf const/foo bar/baz/bing: } $path test oo-clay-leaf-0005 "Test leaf: const/foo/bar baz bing" { ::clay::leaf const/foo/bar baz bing } $path test oo-clay-leaf-0006 "Test leaf: const/foo/bar baz bing:" { ::clay::leaf const/foo/bar baz bing: } $path test oo-clay-leaf-0007 "Test leaf: const foo/bar/baz/bing" { ::clay::leaf const foo/bar/baz/bing } $path test oo-clay-leaf-0008 "Test leaf: const foo bar/baz/bing" { ::clay::leaf const foo bar/baz/bing } $path test oo-clay-leaf-0009 "Test leaf: const/foo bar baz bing" { ::clay::leaf const/foo bar baz bing } $path namespace eval ::foo {} clay::define ::foo::classa { clay set const color blue clay set const/flavor strawberry clay set {const/ sound} zoink clay set info/ { animal no building no subelement {pedantic yes} } } test oo-class-clay-method-0001 "Test ::foo::classa const/ color exists" { ::foo::classa clay exists const/ color } 1 test oo-class-clay-method-0001 "Test ::foo::classa const/ color value" { ::foo::classa clay get const/ color } {blue} test oo-class-clay-method-0003 "Test ::foo::classa const/ flavor exists" { ::foo::classa clay exists const/ flavor } 1 test oo-class-clay-method-0003 "Test ::foo::classa const/ flavor value" { ::foo::classa clay get const/ flavor } {strawberry} test oo-class-clay-method-0005 "Test ::foo::classa const/ sound exists" { ::foo::classa clay exists const/ sound } 1 test oo-class-clay-method-0005 "Test ::foo::classa const/ sound value" { ::foo::classa clay get const/ sound } {zoink} test oo-class-clay-method-0007 "Test ::foo::classa info/ animal exists" { ::foo::classa clay exists info/ animal } 1 test oo-class-clay-method-0007 "Test ::foo::classa info/ animal value" { ::foo::classa clay get info/ animal } {no} test oo-class-clay-method-0009 "Test ::foo::classa info/ building exists" { ::foo::classa clay exists info/ building } 1 test oo-class-clay-method-0009 "Test ::foo::classa info/ building value" { ::foo::classa clay get info/ building } {no} test oo-class-clay-method-0011 "Test ::foo::classa info/ subelement exists" { ::foo::classa clay exists info/ subelement } 1 test oo-class-clay-method-0011 "Test ::foo::classa info/ subelement value" { ::foo::classa clay get info/ subelement } {pedantic yes} clay::define ::foo::classb { clay set const/ color black clay set const/ flavor vanilla clay set const/ feeling dread clay set info/ subelement {spoon yes} } test oo-class-clay-method-0013 "Test ::foo::classb const/ color exists" { ::foo::classb clay exists const/ color } 1 test oo-class-clay-method-0013 "Test ::foo::classb const/ color value" { ::foo::classb clay get const/ color } {black} test oo-class-clay-method-0015 "Test ::foo::classb const/ flavor exists" { ::foo::classb clay exists const/ flavor } 1 test oo-class-clay-method-0015 "Test ::foo::classb const/ flavor value" { ::foo::classb clay get const/ flavor } {vanilla} test oo-class-clay-method-0017 "Test ::foo::classb const/ feeling exists" { ::foo::classb clay exists const/ feeling } 1 test oo-class-clay-method-0017 "Test ::foo::classb const/ feeling value" { ::foo::classb clay get const/ feeling } {dread} test oo-class-clay-method-0019 "Test ::foo::classb info/ subelement exists" { ::foo::classb clay exists info/ subelement } 1 test oo-class-clay-method-0019 "Test ::foo::classb info/ subelement value" { ::foo::classb clay get info/ subelement } {spoon yes} clay::define ::foo::class.ab { superclass ::foo::classb ::foo::classa } clay::define ::foo::class.ba { superclass ::foo::classa ::foo::classb } # ------------------------------------------------------------------------- # OBJECT of ::foo::classa set OBJECTA [::foo::classa new] ### # Test object degation ### proc ::foo::fakeobject {a b} { return [expr {$a + $b}] } ::clay::object create TEST TEST clay delegate funct ::foo::fakeobject test oo-object-delegate-001 {Test object delegation} { ::TEST clay delegate } {<class> ::clay::object <funct> ::foo::fakeobject} test oo-object-delegate-002 {Test object delegation} { ::TEST clay delegate funct } {::foo::fakeobject} test oo-object-delegate-002a {Test object delegation} { ::TEST clay delegate <funct> } {::foo::fakeobject} test oo-object-delegate-003 {Test object delegation} { ::TEST <funct> 1 1 } {2} test oo-object-delegate-004 {Test object delegation} { ::TEST <funct> 10 -7 } {3} # Replace the function out from under proc ::foo::fakeobject {a b} { return [expr {$a * $b}] } test oo-object-delegate-005 {Test object delegation} { ::TEST <funct> 10 -7 } {-70} # Object with ::foo::classa mixed in set MIXINA [::oo::object new] oo::objdefine $MIXINA mixin ::foo::classa test oo-object-clay-method-native-0001 {Test native object gets the property} { $OBJECTA clay get const/ color } {blue} test oo-object-clay-method-mixin-0001 {Test mixin object gets the property} { $MIXINA clay get const/ color } {blue} test oo-object-clay-method-native-0002 {Test native object gets the property} { $OBJECTA clay get const/ flavor } {strawberry} test oo-object-clay-method-mixin-0002 {Test mixin object gets the property} { $MIXINA clay get const/ flavor } {strawberry} test oo-object-clay-method-native-0003 {Test native object gets the property} { $OBJECTA clay get const/ sound } {zoink} test oo-object-clay-method-mixin-0003 {Test mixin object gets the property} { $MIXINA clay get const/ sound } {zoink} test oo-object-clay-method-native-0004 {Test native object gets the property} { $OBJECTA clay get info/ animal } {no} test oo-object-clay-method-mixin-0004 {Test mixin object gets the property} { $MIXINA clay get info/ animal } {no} test oo-object-clay-method-native-0005 {Test native object gets the property} { $OBJECTA clay get info/ building } {no} test oo-object-clay-method-mixin-0005 {Test mixin object gets the property} { $MIXINA clay get info/ building } {no} test oo-object-clay-method-native-0006 {Test native object gets the property} { $OBJECTA clay get info/ subelement } {pedantic yes} test oo-object-clay-method-mixin-0006 {Test mixin object gets the property} { $MIXINA clay get info/ subelement } {pedantic yes} # ------------------------------------------------------------------------- # OBJECT of ::foo::classb set OBJECTB [::foo::classb new] # Object with ::foo::classb mixed in set MIXINB [::oo::object new] oo::objdefine $MIXINB mixin ::foo::classb test oo-object-clay-method-native-0007 {Test native object gets the property} { $OBJECTB clay get const/ color } {black} test oo-object-clay-method-mixin-0007 {Test mixin object gets the property} { $MIXINB clay get const/ color } {black} test oo-object-clay-method-native-0008 {Test native object gets the property} { $OBJECTB clay get const/ flavor } {vanilla} test oo-object-clay-method-mixin-0008 {Test mixin object gets the property} { $MIXINB clay get const/ flavor } {vanilla} test oo-object-clay-method-native-0009 {Test native object gets the property} { $OBJECTB clay get const/ feeling } {dread} test oo-object-clay-method-mixin-0009 {Test mixin object gets the property} { $MIXINB clay get const/ feeling } {dread} test oo-object-clay-method-native-0010 {Test native object gets the property} { $OBJECTB clay get info/ subelement } {spoon yes} test oo-object-clay-method-mixin-0010 {Test mixin object gets the property} { $MIXINB clay get info/ subelement } {spoon yes} # ------------------------------------------------------------------------- # OBJECT descended from ::foo::classa ::foo::classb set OBJECTAB [::foo::class.ab new] # Object where classes were mixed in ::foo::classa ::foo::classb set MIXINAB [::oo::object new] oo::objdefine $MIXINAB mixin ::foo::classa ::foo::classb test oo-object-clay-method-native-0011 {Test native object gets the property} { $OBJECTAB clay get const/ color } {black} test oo-object-clay-method-mixin-0011 {Test mixin object gets the property} { $MIXINAB clay get const/ color } {black} test oo-object-clay-method-native-0012 {Test native object gets the property} { $OBJECTAB clay get const/ flavor } {vanilla} test oo-object-clay-method-mixin-0012 {Test mixin object gets the property} { $MIXINAB clay get const/ flavor } {vanilla} test oo-object-clay-method-native-0013 {Test native object gets the property} { $OBJECTAB clay get const/ feeling } {dread} test oo-object-clay-method-mixin-0013 {Test mixin object gets the property} { $MIXINAB clay get const/ feeling } {dread} test oo-object-clay-method-native-0014 {Test native object gets the property} { $OBJECTAB clay get const/ sound } {zoink} test oo-object-clay-method-mixin-0014 {Test mixin object gets the property} { $MIXINAB clay get const/ sound } {zoink} test oo-object-clay-method-native-0015 {Test native object gets the property} { $OBJECTAB clay get info/ subelement } {spoon yes} test oo-object-clay-method-mixin-0015 {Test mixin object gets the property} { $MIXINAB clay get info/ subelement } {spoon yes} test oo-object-clay-method-native-0016 {Test native object gets the property} { $OBJECTAB clay get info/ animal } {no} test oo-object-clay-method-mixin-0016 {Test mixin object gets the property} { $MIXINAB clay get info/ animal } {no} test oo-object-clay-method-native-0017 {Test native object gets the property} { $OBJECTAB clay get info/ building } {no} test oo-object-clay-method-mixin-0017 {Test mixin object gets the property} { $MIXINAB clay get info/ building } {no} # ------------------------------------------------------------------------- # OBJECT descended from ::foo::classb ::foo::classa set OBJECTBA [::foo::class.ba new] # Object where classes were mixed in ::foo::classb ::foo::classa set MIXINBA [::oo::object new] oo::objdefine $MIXINBA mixin ::foo::classb ::foo::classa test oo-object-clay-method-native-0018 {Test native object gets the property} { $OBJECTBA clay get const/ color } {blue} test oo-object-clay-method-mixin-0018 {Test mixin object gets the property} { $MIXINBA clay get const/ color } {blue} test oo-object-clay-method-native-0019 {Test native object gets the property} { $OBJECTBA clay get const/ flavor } {strawberry} test oo-object-clay-method-mixin-0019 {Test mixin object gets the property} { $MIXINBA clay get const/ flavor } {strawberry} test oo-object-clay-method-native-0020 {Test native object gets the property} { $OBJECTBA clay get const/ sound } {zoink} test oo-object-clay-method-mixin-0020 {Test mixin object gets the property} { $MIXINBA clay get const/ sound } {zoink} test oo-object-clay-method-native-0021 {Test native object gets the property} { $OBJECTBA clay get const/ feeling } {dread} test oo-object-clay-method-mixin-0021 {Test mixin object gets the property} { $MIXINBA clay get const/ feeling } {dread} test oo-object-clay-method-native-0022 {Test native object gets the property} { $OBJECTBA clay get info/ animal } {no} test oo-object-clay-method-mixin-0022 {Test mixin object gets the property} { $MIXINBA clay get info/ animal } {no} test oo-object-clay-method-native-0023 {Test native object gets the property} { $OBJECTBA clay get info/ building } {no} test oo-object-clay-method-mixin-0023 {Test mixin object gets the property} { $MIXINBA clay get info/ building } {no} test oo-object-clay-method-native-0024 {Test native object gets the property} { $OBJECTBA clay get info/ subelement } {pedantic yes} test oo-object-clay-method-mixin-0024 {Test mixin object gets the property} { $MIXINBA clay get info/ subelement } {pedantic yes} ### # put a do-nothing constructor on the books ### ::clay::define ::clay::object { constructor args {} } oo::objdefine ::clay::object method foo args { return bar } test clay-core-method-0001 {Test that adding methods to the core ::clay::object class works} { ::clay::object foo } {bar} namespace eval ::TEST {} ::clay::define ::TEST::myclass { clay color red clay flavor strawberry } ### # Test adding a clay property ### test clay-class-clay-0001 {Test that a clay statement is recorded in the object of the class} { ::TEST::myclass clay get color } red test clay-class-clay-0002 {Test that a clay statement is recorded in the object of the class} { ::TEST::myclass clay get flavor } strawberry ### # Test that objects of the class get the same properties ### set OBJ [::clay::object new {}] set OBJ2 [::TEST::myclass new {}] test clay-object-clay-a-0001 {Test that objects not thee class do not get properties} { $OBJ clay get color } {} test clay-object-clay-a-0002 {Test that objects not thee class do not get properties} { $OBJ clay get flavor } {} test clay-object-clay-a-0003 {Test that objects of the class get properties} { $OBJ2 clay get color } red test clay-object-clay-a-0004 {Test that objects of the class get properties} { $OBJ2 clay get flavor } strawberry test clay-object-clay-a-0005 {Test the clay ancestors function} { $OBJ clay ancestors } {::clay::object ::oo::object} test clay-object-clay-a-0006 {Test the clay ancestors function} { $OBJ2 clay ancestors } {::TEST::myclass ::clay::object ::oo::object} test clay-object-clay-a-0007 {Test the clay provenance function} { $OBJ2 clay provenance flavor } ::TEST::myclass ### # Test that object local setting override the class ### test clay-object-clay-a-0008 {Test that object local setting override the class} { $OBJ2 clay set color purple $OBJ2 clay get color } purple test clay-object-clay-a-0009 {Test that object local setting override the class} { $OBJ2 clay provenance color } self ::clay::define ::TEST::myclasse { superclass ::TEST::myclass clay color blue method do args { return "I did $args" } Ensemble which::color {} { return [my clay get color] } } ### # Test clay information is passed town to subclasses ### test clay-class-clay-0003 {Test that a clay statement is recorded in the object of the class} { ::TEST::myclasse clay get color } blue test clay-class-clay-0004 {Test that clay statements from the ancestors of this class are not present (we handle them seperately in objects)} { ::TEST::myclasse clay get flavor } {strawberry} ### # Test that properties reach objects ### set OBJ3 [::TEST::myclasse new {}] test clay-object-clay-b-0001 {Test that objects of the class get properties} { $OBJ3 clay get color } blue test clay-object-clay-b-0002 {Test the clay provenance function} { $OBJ3 clay provenance color } ::TEST::myclasse test clay-object-clay-b-0003 {Test that objects of the class get properties} { $OBJ3 clay get flavor } strawberry test clay-object-clay-b-0004 {Test the clay provenance function} { $OBJ3 clay provenance flavor } ::TEST::myclass test clay-object-clay-b-0005 {Test the clay provenance function} { $OBJ3 clay ancestors } {::TEST::myclasse ::TEST::myclass ::clay::object ::oo::object} ### # Test defining a standard method ### test clay-object-method-0001 {Test and standard method} { $OBJ3 do this really cool thing } {I did this really cool thing} test clay-object-method-0003 {Test an ensemble} { $OBJ3 which color } blue # Test setting properties test clay-object-method-0004 {Test an ensemble} { $OBJ3 clay set color black $OBJ3 which color } black ### # Test that if you try to replace a global command you get an error ### test clay-nspace-0001 {Test that if you try to replace a global command you get an error} -body { ::clay::define open { method bar {} { return foo } } } -returnCodes {error} -result "::open does not refer to an object" ::clay::define fubar { method bar {} { return foo } } test clay-nspace-0002 {Test a non qualified class ends up in the current namespace} { info commands ::fubar } {::fubar} namespace eval ::cluster { ::clay::define fubar { method bar {} { return foo } } ::clay::define ::clay::pot { method bar {} { return foo } } } test clay-nspace-0003 {Test a non qualified class ends up in the current namespace} { info commands ::cluster::fubar } {::cluster::fubar} test clay-nspace-0003 {Test a fully qualified class ends up in the proper namespace} { info commands ::clay::pot } {::clay::pot} #set ::clay::trace 3 ### # Mixin tests ### ### # Define a core class ### ::clay::define ::TEST::thing { method do args { return "I did $args" } } ::clay::define ::TEST::vegetable { clay color unknown clay flavor unknown Ensemble which::flavor {} { return [my clay get flavor] } Ensemble which::color {} { return [my clay get color] } } ::clay::define ::TEST::animal { clay color unknown clay sound unknown Ensemble which::sound {} { return [my clay get sound] } Ensemble which::color {} { return [my clay get color] } } ::clay::define ::TEST::species.cat { superclass ::TEST::animal clay sound meow } ::clay::define ::TEST::coloring.calico { clay color calico } ::clay::define ::TEST::condition.dark { Ensemble which::color {} { return grey } } ::clay::define ::TEST::mood.happy { Ensemble which::sound {} { return purr } } test clay-object-0001 {Test than an object is created when clay::define is invoked} { info commands ::TEST::mood.happy } ::TEST::mood.happy set OBJ [::TEST::thing new] test clay-mixin-a-0001 {Test that prior to a mixin an ensemble doesn't exist} -body { $OBJ which color } -returnCodes error -result {unknown method "which": must be clay, destroy or do} test clay-mixin-a-0002 {Test and standard method from an ancestor} { $OBJ do this really cool thing } {I did this really cool thing} $OBJ clay mixinmap species ::TEST::animal test clay-mixin-b-0001 {Test that an ensemble is created during a mixin} { $OBJ which color } {unknown} test clay-mixin-b-0002 {Test that an ensemble is created during a mixin} { $OBJ which sound } {unknown} test clay-mixin-b-0003 {Test that an ensemble is created during a mixin} -body {$OBJ which flavor} -returnCodes {error} -result {unknown method which flavor. Valid: color sound} test clay-mixin-b-0004 {Test that mixins resolve in the correct order} { $OBJ clay ancestors } {::TEST::animal ::TEST::thing ::clay::object ::oo::object} ### # Replacing a mixin replaces the behaviors ### $OBJ clay mixinmap species ::TEST::vegetable test clay-mixin-c-0001 {Test that an ensemble is created during a mixin} { $OBJ which color } {unknown} test clay-mixin-c-0002 {Test that an ensemble is created during a mixin} -body {$OBJ which sound} -returnCodes {error} -result {unknown method which sound. Valid: color flavor} test clay-mixin-c-0003 {Test that an ensemble is created during a mixin} { $OBJ which flavor } {unknown} test clay-mixin-c-0004 {Test that mixins resolve in the correct order} { $OBJ clay ancestors } {::TEST::vegetable ::TEST::thing ::clay::object ::oo::object} ### # Replacing a mixin $OBJ clay mixinmap species ::TEST::species.cat test clay-mixin-e-0001 {Test that an ensemble is created during a mixin} { $OBJ which color } {unknown} test clay-mixin-e-0002 {Test that an ensemble is created during a mixin} { $OBJ which sound } {meow} test clay-mixin-e-0003 {Test that an ensemble is created during a mixin} -body {$OBJ which flavor} -returnCodes {error} -result {unknown method which flavor. Valid: color sound} test clay-mixin-e-0004 {Test that clay data follows the rules of inheritence and order of mixin} { $OBJ clay ancestors } {::TEST::species.cat ::TEST::thing ::TEST::animal ::clay::object ::oo::object} $OBJ clay mixinmap coloring ::TEST::coloring.calico test clay-mixin-f-0001 {Test that an ensemble is created during a mixin} { $OBJ which color } {calico} test clay-mixin-f-0002 {Test that an ensemble is created during a mixin} { $OBJ which sound } {meow} test clay-mixin-f-0003 {Test that an ensemble is created during a mixin} -body {$OBJ which flavor} -returnCodes {error} -result {unknown method which flavor. Valid: color sound} test clay-mixin-f-0004 {Test that clay data follows the rules of inheritence and order of mixin} { $OBJ clay ancestors } {::TEST::coloring.calico ::TEST::species.cat ::TEST::thing ::clay::object ::TEST::animal ::oo::object} test clay-mixin-f-0005 {Test that clay data from a mixin works} { $OBJ clay provenance color } {::TEST::coloring.calico} ### # Test variable initialization ### ::clay::define ::TEST::has_var { Variable my_variable 10 method get_my_variable {} { my variable my_variable return $my_variable } } set OBJ [::TEST::has_var new] test clay-class-variable-0001 {Test that the parser injected the right value in the right place for clay to catch it} { $OBJ clay get variable/ my_variable } {10} test clay-class-variable-0002 {Test that variables declared in the class definition are initialized} { $OBJ get_my_variable } 10 ### # Test array initialization ### ::clay::define ::TEST::has_array { Array my_array {timeout 10} method get_my_array {field} { my variable my_array return $my_array($field) } } set OBJ [::TEST::has_array new] test clay-class-array-0001 {Test that the parser injected the right value in the right place for clay to catch it} { $OBJ clay get array/ } {my_array/ {timeout 10}} test clay-class-arrau-0002 {Test that variables declared in the class definition are initialized} { $OBJ get_my_array timeout } 10 ### # Test dict initialization ### ::clay::define ::TEST::has_dict { Dict my_dict {timeout 10} method get_my_dict {args} { my variable my_dict return [dict get $my_dict {*}$args] } } set OBJ [::TEST::has_dict new] test clay-class-dict-0001 {Test that the parser injected the right value in the right place for clay to catch it} { $OBJ clay get dict/ } {my_dict/ {timeout 10}} test clay-class-dict-0002 {Test that variables declared in the class definition are initialized} { $OBJ get_my_dict timeout } 10 ### # Test object delegation ### ::clay::define ::TEST::organelle { method add args { set total 0 foreach item $args { set total [expr {$total+$item}] } return $total } } ::clay::define ::TEST::master { constructor {} { set mysub [namespace current]::sub ::TEST::organelle create $mysub my clay delegate sub $mysub } } set OBJ [::TEST::master new] ### # Test that delegation is working ### test clay-delegation-0001 {Test an array driven ensemble} { $OBJ <sub> add 5 5 } 10 ### # Test the Ensemble keyword ### ::clay::define ::TEST::with_ensemble { Ensemble myensemble {pattern args} { set ensemble [self method] set emap [my clay ensemble_map $ensemble] set mlist [dict keys $emap [string tolower $pattern]] if {[llength $mlist] != 1} { error "Couldn't figure out what to do with $pattern" } set method [lindex $mlist 0] set arglist [dict get $emap $method arglist] set body [dict get $emap $method body] if {$arglist ni {args {}}} { ::clay::dynamic_arguments $ensemble $method [list $arglist] {*}$args } eval $body } Ensemble myensemble::go args { return 1 } } ::clay::define ::TEST::with_ensemble.dance { Ensemble myensemble::dance args { return 1 } } ::clay::define ::TEST::with_ensemble.cannot_dance { Ensemble myensemble::dance args { return 0 } } set OBJA [::clay::object new] set OBJB [::clay::object new] $OBJA clay mixinmap core ::TEST::with_ensemble friends ::TEST::with_ensemble.dance $OBJB clay mixinmap core ::TEST::with_ensemble friends ::TEST::with_ensemble.cannot_dance # Test go test clay-dynamic-ensemble-0001 {Test ensemble with static method} { $OBJA myensemble go } {1} test clay-dynamic-ensemble-0002 {Test ensemble with static method} { $OBJB myensemble go } {1} # Test dance test clay-dynamic-ensemble-0003 {Test ensemble with static method} { $OBJA myensemble dance } {1} test clay-dynamic-ensemble-0004 {Test ensemble with static method} { $OBJB myensemble dance } {0} ### # Class method testing ### clay::class create WidgetClass { class_method working {} { return {Works} } class_method unknown args { set tkpath [lindex $args 0] if {[string index $tkpath 0] eq "."} { set obj [my new $tkpath {*}[lrange $args 1 end]] $obj tkalias $tkpath return $tkpath } next {*}$args } constructor {TkPath args} { my variable hull set hull $TkPath my clay delegate hull $TkPath } method tkalias tkname { set oldname $tkname my variable tkalias set tkalias $tkname set self [self] set hullwidget [::info object namespace $self]::tkwidget my clay delegate tkwidget $hullwidget #rename ::$tkalias $hullwidget my clay delegate hullwidget $hullwidget #::tool::object_rename [self] ::$tkalias rename [self] ::$tkalias #my Hull_Bind $tkname return $hullwidget } } test tool-class-method-000 {Test that class methods actually work...} { WidgetClass working } {Works} test tool-class-method-001 {Test Tk style creator} { WidgetClass .foo .foo clay delegate hull } {.foo} ::clay::define WidgetNewClass { superclass WidgetClass } test tool-class-method-002 {Test Tk style creator inherited by morph} { WidgetNewClass .bar .bar clay delegate hull } {.bar} ### # Test ensemble inheritence ### clay::define NestedClassA { Ensemble do::family {} { return NestedClassA } Ensemble do::something {} { return A } Ensemble do::whop {} { return A } } clay::define NestedClassB { superclass NestedClassA Ensemble do::family {} { set r [next family] lappend r NestedClassB return $r } Ensemble do::whop {} { return B } } clay::define NestedClassC { superclass NestedClassB Ensemble do::somethingelse {} { return C } } clay::define NestedClassD { superclass NestedClassB Ensemble do::somethingelse {} { return D } } clay::define NestedClassE { superclass NestedClassD NestedClassC } clay::define NestedClassF { superclass NestedClassC NestedClassD } NestedClassC create NestedObjectC ### # These tests no longer work because method ensembles are now dynamically # generated by object, that are not attached to the class anymore # #### #test tool-ensemble-001 {Test that an ensemble can access [next] even if no object of the ancestor class have been instantiated} { # NestedObjectC do family #} {::NestedClassA ::NestedClassB ::NestedClassC} test tool-ensemble-002 {Test that a later ensemble definition trumps a more primitive one} { NestedObjectC do whop } {B} test tool-ensemble-003 {Test that an ensemble definitions in an ancestor carry over} { NestedObjectC do something } {A} NestedClassE create NestedObjectE NestedClassF create NestedObjectF test tool-ensemble-004 {Test that ensembles follow the same rules for inheritance as methods} { NestedObjectE do somethingelse } {D} test tool-ensemble-005 {Test that ensembles follow the same rules for inheritance as methods} { NestedObjectF do somethingelse } {C} ### # Set of tests to exercise the mixinmap system ### clay::define MixinMainClass { Variable mainvar unchanged Ensemble test::which {} { my variable mainvar return $mainvar } Ensemble test::main args { puts [list this is main $method $args] } } set mixoutscript {my test untool $class} set mixinscript {my test tool $class} clay::define MixinTool { Variable toolvar unchanged.mixin clay set mixin/ unmap-script $mixoutscript clay set mixin/ map-script $mixinscript clay set mixin/ name {Generic Tool} Ensemble test::untool class { my variable toolvar mainvar set mainvar {} set toolvar {} } Ensemble test::tool class { my variable toolvar mainvar set mainvar [$class clay get mixin/ name] set toolvar [$class clay get mixin/ name] } } clay::define MixinToolA { superclass MixinTool clay set mixin/ name {Tool A} } clay::define MixinToolB { superclass MixinTool clay set mixin/ name {Tool B} method test_newfunc {} { return "B" } } test tool-mixinspec-001 {Test application of mixin specs} { MixinTool clay get mixin/ map-script } $mixinscript test tool-mixinspec-002 {Test application of mixin specs} { MixinToolA clay get mixin/ map-script } $mixinscript test tool-mixinspec-003 {Test application of mixin specs} { MixinToolB clay get mixin/ map-script } $mixinscript MixinMainClass create mixintest test tool-mixinmap-001 {Test object prior to mixins} { mixintest test which } {unchanged} mixintest clay mixinmap tool MixinToolA test tool-mixinmap-002 {Test mixin map script ran} { mixintest test which } {Tool A} mixintest clay mixinmap tool MixinToolB test tool-mixinmap-003 {Test mixin map script ran} { mixintest test which } {Tool B} test tool-mixinmap-003 {Test mixin map script ran} { mixintest test_newfunc } {B} mixintest clay mixinmap tool {} test tool-mixinmap-004 {Test object prior to mixins} { mixintest test which } {} testsuiteCleanup # Local variables: # mode: tcl # indent-tabs-mode: nil # End: |
Added modules/clay/pkgIndex.tcl.
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. if {![package vsatisfies [package provide Tcl] 8.6]} {return} package ifneeded clay 0.3 [list source [file join $dir clay.tcl]] package ifneeded oo::meta 0.8 [list source [file join $dir clay.tcl]] |
Changes to modules/cron/cron.man.
︙ | ︙ | |||
119 120 121 122 123 124 125 | [call [cmd {::cron::task info}] [arg process]] Returns a dict describing [arg process]. See [cmd {::cron::task set}] for a description of the options. [call [cmd {::cron::task set}] [arg process] [arg field] [arg value] [arg ?field...?] [arg ?value...?]] [para] If [arg process] does not exist, it is created. Options Include: [list_begin definitions] | | | | | | | | | | | | | | | | 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 | [call [cmd {::cron::task info}] [arg process]] Returns a dict describing [arg process]. See [cmd {::cron::task set}] for a description of the options. [call [cmd {::cron::task set}] [arg process] [arg field] [arg value] [arg ?field...?] [arg ?value...?]] [para] If [arg process] does not exist, it is created. Options Include: [list_begin definitions] [def [cmd command]] If [cmd coroutine] is black, a global command which implements this process. If [cmd coroutine] is not black, the command to invoke to create or recreate the coroutine. [def [cmd coroutine]] The name of the coroutine (if any) which implements this process. [def [cmd frequency]] If -1, this process is terminated after the next event. If 0 this process should be called during every idle event. If positive, this process should generate events periodically. The frequency is an integer number of milliseconds between events. [def [cmd object]] The object associated with this process or coroutine. [def [cmd scheduled]] If non-zero, the absolute time from the epoch (in milliseconds) that this process will trigger an event. If zero, and the [cmd frequency] is also zero, this process is called every idle loop. [def [cmd running]] A boolean flag. If true it indicates the process never returned or yielded during the event loop, and will not be called again until it does so. [list_end] [call [cmd ::cron::wake] [arg ?who?]] Wake up cron, and arrange for its event loop to be run during the next Idle cycle. [example_begin] ::cron::wake {I just did something important} [example_end] [list_end] [para] Several utility commands are provided that are used internally within cron and for testing cron, but may or may not be useful in the general cases. [list_begin definitions] [call [cmd ::cron::clock_step] [arg milliseconds]] [para] Return a clock time absolute to the epoch which falls on the next border between one second and the next for the value of [arg milliseconds] [call [cmd ::cron::clock_delay] [arg milliseconds]] [para] Return a clock time absolute to the epoch which falls on the next border between one second and the next [arg milliseconds] in the future. [call [cmd ::cron::clock_sleep] [arg seconds] [arg ?offset?]] [para] Return a clock time absolute to the epoch which falls exactly [arg seconds] in the future. If offset is given it may be positive or negative, and will shift the final time to before or after the second would flip. [call [cmd ::cron::clock_set] [arg newtime]] [para] Sets the internal clock for cron. This command will advance the time in 100ms increment, triggering events, until the internal time catches up with [arg newtime]. [para] [arg newtime] is expressed in absolute milliseconds since the beginning of the epoch. [list_end] [para] [vset CATEGORY odie] [include ../doctools2base/include/feedback.inc] [manpage_end] |
Changes to modules/cron/cron.tcl.
︙ | ︙ | |||
262 263 264 265 266 267 268 | } proc ::cron::once_in_a_while body { set script {set _eventid_ $::cron::current_event} append script $body # Add a safety to allow this while to only execute once per call append script {if {$_eventid_==$::cron::current_event} yield} | | | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | } proc ::cron::once_in_a_while body { set script {set _eventid_ $::cron::current_event} append script $body # Add a safety to allow this while to only execute once per call append script {if {$_eventid_==$::cron::current_event} yield} uplevel 1 [list while 1 $script] } proc ::cron::sleep ms { if {$::cron::trace > 1} { puts [list ::cron::sleep $ms [info coroutine]] } |
︙ | ︙ |
Changes to modules/doctools/cvs.man.
︙ | ︙ | |||
81 82 83 84 85 86 87 | [para] The values are lists of the files the entry is touching. [list_end] [para] | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | [para] The values are lists of the files the entry is touching. [list_end] [para] [call [cmd ::doctools::cvs::toChangeLog] [arg evar] [arg cvar] [arg fvar]] The three arguments for this command are the same as the last three arguments of the command [cmd ::doctools::cvs::scanLog]. This command however expects them to be filled with information about one or more logs. It takes this information and converts it into a text in the format of a ChangeLog as accepted and generated by [syscmd emacs]. The constructed text is returned as the result of the command. |
︙ | ︙ |
Changes to modules/doctools/doctools_lang_intro.man.
︙ | ︙ | |||
116 117 118 119 120 121 122 | [para] Given the above a less minimal example of a document is [example_begin] [lb]manpage_begin NAME SECTION VERSION[rb] | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | [para] Given the above a less minimal example of a document is [example_begin] [lb]manpage_begin NAME SECTION VERSION[rb] [lb][cmd {copyright {YEAR AUTHOR}}][rb] [lb][cmd {titledesc TITLE}][rb] [lb][cmd {moddesc MODULE_TITLE}][rb] [lb][cmd {require PACKAGE VERSION}][rb] [lb][cmd {require PACKAGE}][rb] [lb]description[rb] [lb]manpage_end[rb] [example_end] Remember that the whitespace is optional. The document [example { [manpage_begin NAME SECTION VERSION] [copyright {YEAR AUTHOR}][titledesc TITLE][moddesc MODULE_TITLE] [require PACKAGE VERSION][require PACKAGE][description] [vset CATEGORY doctools] [include ../doctools2base/include/feedback.inc] [manpage_end] }] has the same meaning as the example before. [para] On the other hand, if [term whitespace] is present it consists not only of any sequence of characters containing the space character, horizontal and vertical tabs, carriage return, and newline, but it may contain comment markup as well, in the form of the [cmd comment] command. [example_begin] [lb][cmd {comment { ... }}][rb] [lb]manpage_begin NAME SECTION VERSION[rb] [lb]copyright {YEAR AUTHOR}[rb] [lb]titledesc TITLE[rb] [lb]moddesc MODULE_TITLE[rb][lb][cmd {comment { ... }}][rb] [lb]require PACKAGE VERSION[rb] [lb]require PACKAGE[rb] [lb]description[rb] [lb]manpage_end[rb] [lb][cmd {comment { ... }}][rb] [example_end] [subsection {Advanced structure}] In the simple examples of the last section we fudged a bit regarding the markup actually allowed to be used before the [cmd manpage_begin] command opening the document. [para] Instead of only whitespace the two templating commands [cmd include] and [cmd vset] are also allowed, to enable the writer to either set and/or import configuration settings relevant to the document. I.e. it is possible to write [example_begin] [lb][cmd {include FILE}][rb] [lb][cmd {vset VAR VALUE}][rb] [lb]manpage_begin NAME SECTION VERSION[rb] [lb]description[rb] [lb]manpage_end[rb] [example_end] Even more important, these two commands are allowed anywhere where a markup command is allowed, without regard for any other structure. I.e. for example in the header as well. [example_begin] [lb]manpage_begin NAME SECTION VERSION[rb] [lb][cmd {include FILE}][rb] [lb][cmd {vset VAR VALUE}][rb] [lb]description[rb] [lb]manpage_end[rb] [example_end] The only restriction [cmd include] has to obey is that the contents of the included file must be valid at the place of the inclusion. I.e. a file included before [cmd manpage_begin] may contain only the templating commands [cmd vset] and [cmd include], a file included in the header may contain only header commands, etc. [subsection {Text structure}] The body of the document consists mainly of text, possibly split into sections, subsections, and paragraphs, with parts marked up to |
︙ | ︙ | |||
291 292 293 294 295 296 297 | of this command closes the previous paragraph and automatically opens the next. The first paragraph is automatically opened at the beginning of the body, by [cmd description]. In the same manner the last paragraph automatically ends at [cmd manpage_end]. [example_begin] [lb]manpage_begin NAME SECTION VERSION[rb] | < < < < < < < < < < | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | of this command closes the previous paragraph and automatically opens the next. The first paragraph is automatically opened at the beginning of the body, by [cmd description]. In the same manner the last paragraph automatically ends at [cmd manpage_end]. [example_begin] [lb]manpage_begin NAME SECTION VERSION[rb] [lb]description[rb] ... [lb][cmd para][rb] ... [lb][cmd para][rb] ... [lb]manpage_end[rb] |
︙ | ︙ | |||
330 331 332 333 334 335 336 | [para] Empty sections are [emph not] ignored. We are free to (not) use paragraphs within sections. [example_begin] [lb]manpage_begin NAME SECTION VERSION[rb] | < < < < < < < < < < | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | [para] Empty sections are [emph not] ignored. We are free to (not) use paragraphs within sections. [example_begin] [lb]manpage_begin NAME SECTION VERSION[rb] [lb]description[rb] ... [lb][cmd {section {Section A}}][rb] ... [lb]para[rb] ... [lb][cmd {section {Section B}}][rb] |
︙ | ︙ | |||
367 368 369 370 371 372 373 | [para] Empty subsections are [emph not] ignored. We are free to (not) use paragraphs within subsections. [example_begin] [lb]manpage_begin NAME SECTION VERSION[rb] | < < < < < < < < < < | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | [para] Empty subsections are [emph not] ignored. We are free to (not) use paragraphs within subsections. [example_begin] [lb]manpage_begin NAME SECTION VERSION[rb] [lb]description[rb] ... [lb]section {Section A}[rb] ... [lb][cmd {subsection {Sub 1}}][rb] ... [lb]para[rb] |
︙ | ︙ | |||
452 453 454 455 456 457 458 | highlighting added. It shows their use within a block of text, as the arguments of a list item command ([cmd call]), and our ability to nest them. [example_begin] ... | | | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | highlighting added. It shows their use within a block of text, as the arguments of a list item command ([cmd call]), and our ability to nest them. [example_begin] ... [lb]call [lb][cmd {cmd arg_def}][rb] [lb][cmd {arg type}][rb] [lb][cmd {arg name}][rb] [lb][cmd opt] [lb][cmd {arg mode}][rb][rb][rb] Text structure. List element. Argument list. Automatically closes the previous list element. Specifies the data-[lb][cmd {arg type}][rb] of the described argument of a command, its [lb][cmd {arg name}][rb] and its i/o-[lb][cmd {arg mode}][rb]. The latter is optional. ... [example_end] |
︙ | ︙ | |||
517 518 519 520 521 522 523 | [list_end] [para] All the cross-reference commands can occur anywhere in the document between [cmd manpage_begin] and [cmd manpage_end]. As such the writer | < < < < < < < < < < | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | [list_end] [para] All the cross-reference commands can occur anywhere in the document between [cmd manpage_begin] and [cmd manpage_end]. As such the writer can choose whether she wants to have them at the beginning of the body, or at its end, maybe near the place a keyword is actually defined by the main content, or considers them as meta data which should be in the header, etc. [para] |
︙ | ︙ |
Changes to modules/fumagic/cfront.man.
︙ | ︙ | |||
27 28 29 30 31 32 33 | [section COMMANDS] [list_begin definitions] [call [cmd ::fileutil::magic::cfront::compile] [arg path]...] | | | | > > | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | [section COMMANDS] [list_begin definitions] [call [cmd ::fileutil::magic::cfront::compile] [arg path]...] This command takes the paths of one or more files and directories and compiles all the files, and the files in all the directories into a single analyzer for all the file types specified in these files. It returns a list whose first item is a list per-file dictionaries of analyzer scripts and whose second item is a list of analyzer commands. [para] All the files have to be in the format specified by magic(5). [para] |
︙ | ︙ |
Changes to modules/fumagic/cfront.tcl.
︙ | ︙ | |||
30 31 32 33 34 35 36 | # file to compile the magic file from magic(5) into a tcl program package require fileutil ; # File processing (input) package require fileutil::magic::cgen ; # Code generator. package require fileutil::magic::rt ; # Runtime (typemap) package require struct::list ; # lrepeat. package require struct::tree ; # | | > > | | > | > > > | < | > | > | | | < | | > > | 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 | # file to compile the magic file from magic(5) into a tcl program package require fileutil ; # File processing (input) package require fileutil::magic::cgen ; # Code generator. package require fileutil::magic::rt ; # Runtime (typemap) package require struct::list ; # lrepeat. package require struct::tree ; # package provide fileutil::magic::cfront 1.3.0 # ### ### ### ######### ######### ######### ## Implementation namespace eval ::fileutil::magic::cfront { # Configuration flag. (De)activate debugging output. # This is done during initialization. # Changes at runtime have no effect. variable debug 0 # Make backend functionality accessible namespace import ::fileutil::magic::cgen namespace export compile generate install namespace upvar ::fileutil::magic::rt typemap typemap variable floattestops {= < > !} variable inttestops {= < > & ^ ~ !} variable stringtestops { > < = !} variable offsetopts {& | ^ + - * / %} variable stringmodifiers {W w c C t b T} variable typemodifiers [dict create \ indirect r \ search $stringmodifiers \ string $stringmodifiers \ pstring [list {*}$stringmodifiers B H h L l J] \ regex {c s l} \ ] set numeric_modifier_allowed {regex search} variable types_numeric_short foreach {shortname name} { dC byte d1 byte C byte 1 byte ds short d2 short S short 2 short dI long dL long d4 long I long L long 4 long d8 quad 8 quad dQ quad Q quad } { dict set types_numeric_short $shortname $name dict set types_numeric_short u$shortname u$name } variable types_numeric_all [list {*}[ array names typemap] {*}[dict keys $types_numeric_short]] variable types_string_short [dict create s string] variable types_string_short [dict create us ustring] variable types_string { bestring clear indirect lestring lestring16 pstring regex search string ustring } variable types_string_all [list {*}[ dict keys $types_string_short] {*}$types_string] variable types_verbatim {name use} variable types_notimplemented {der} variable types_numeric_real foreach name {float double befloat bedouble lefloat ledouble} { lappend types_numeric_real $name u$name } variable indir_typemap [dict create \ b byte c byte e ledouble f ledouble g ledouble i leid3 h leshort \ s leshort l lelong B byte C byte E bedouble F bedouble G bedouble \ H beshort I beid3 L belong m ME S beshort] } proc ::fileutil::magic::cfront::advance {len args} { upvar node node tree tree if {[llength args]} { upvar [lindex $args 0] res } set res {} |
︙ | ︙ | |||
118 119 120 121 122 123 124 | } } set line [$tree get $node line] $tree set $node cursor $cursor return $res } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | } } set line [$tree get $node line] $tree set $node cursor $cursor return $res } # compile up magic files or directories of magic files into a single recognizer. proc ::fileutil::magic::cfront::compile {args} { set tree [tree] foreach arg $args { if {[file type $arg] eq {directory}} { |
︙ | ︙ | |||
781 782 783 784 785 786 787 | ::fileutil::magic::cfront::Debug {puts [treedump $t]} #set tcl [run $script] return [list $named $tests] } | > | > | > > > > > | > > > > > > > > > | | | > > > > > > > > | | > | > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ::fileutil::magic::cfront::Debug {puts [treedump $t]} #set tcl [run $script] return [list $named $tests] } proc ::fileutil::magic::cfront::generate args { set indent {} set pline {} while {[llength $args]} { set args [lassign $args[set args {}] key] switch $key { compressed { set args [lassign $args[set args {}] val] if {$val} { set indent {} set pline {} } else { set indent \t set pline \n } } -- break default { error [list {unknown argument}] } } } lassign [compile {*}$args] named tests append script "variable named {\n" dict for {key val} $named { append script "${indent}[list $key]" append script "$pline${indent}${indent}[list [string map [ list \n \n${indent}] $val]]\n" } append script "$pline}\n" append script "proc analyze {} {\n" foreach item $tests { append script "${indent}[string map [ list \n \n${indent}] $item]\n" } append script "$pline}\n" return $script } proc ::fileutil::magic::cfront::install args { foreach arg $args { set path [file tail $arg] eval [generate compressed 1 -- ::fileutil::magic::/$path $arg] } return } proc ::fileutil::magic::cfront::parseerror args { upvar node node tree tree set cursor [$tree get $node cursor] set line [$tree get $node line] set files [$tree get root files] set file [lindex $files [$tree get $node file]] return -code error -errorcode [list fumagic {parse error}] [ list [lmap arg $args {string trim $arg}] \ file $file \ linenenum [$tree get $node linenum] \ cursor $cursor \ line [list \ [string range $line 0 ${cursor}-1] \ [string range $line $cursor end]]] } proc ::fileutil::magic::cfront::parsewarning args { upvar node node tree tree catch {parseerror {*}$args} res options puts stderr [list parse warning $res] #puts stderr [dict get $options -errorinfo] } # parse an individual line variable ::fileutil::magic::cfront::parsedkeys { } proc ::fileutil::magic::cfront::parseline {tree node} { variable parsedkeys set line [$tree get $node line] $tree set $node cursor 0 parseoffset $tree $node parsetype $tree $node parsetest $tree $node parsemsg $tree $node set record [$tree getall $node] foreach key $parsedkeys { if {![dict exists $record $key]} { return -code error [list {missing key} $key] } } ::fileutil::magic::cfront::Debug { puts [list parsed $record] } } proc ::fileutil::magic::cfront::parsefloat {tree node} { set line [$tree get $node line] set cursor [$tree get $node cursor] # If only [scan] had a @ conversion character like [binary scan] set line2 [string range $line $cursor end] if {[scan $line2 %e%n num count] < 0} { parseerror {invalid floating point number} } set cursor [expr {$cursor + $count}] $tree set $node cursor $cursor # These suffixes are not used in magic files #if {[regexp -start $cursor {\A([fFlL)} -> modifier]} { # advance [string length $modifier]] #} return $num } proc ::fileutil::magic::cfront::parseint {tree node} { set line [$tree get $node line] set cursor [$tree get $node cursor] # If only [scan] had a @ conversion character like [binary scan] set line2 [string range $line $cursor end] if {[set scanres [scan $line2 %lli%n num n]] < 1} { parseerror [list {invalid number} $line2] } set cursor [expr {$cursor + $n}] $tree set $node cursor $cursor # Thse suffixes are not used in magic files #if {[regexp -start $cursor {\A([uU]?[lL]{1,2})} -> modifier]} { # advance [string length $modifier]] #} return $num } proc ::fileutil::magic::cfront::parsetype {tree node} { variable types_numeric_all variable types_numeric_short variable types_string_all variable types_string_short variable types_notimplemented set line [$tree get $node line] set cursor [$tree get $node cursor] $tree set $node mod {} $tree set $node mand {} set num_or_string { } if {[regexp -start $cursor {\A\s*(\w+)} $line match type]} { advance [string length $match] if {$type in $types_numeric_all} { if {[dict exists $types_numeric_short $type]} { set type [dict get $types_numeric_short $type] } $tree set $node type $type parsetypenummod $tree $node } elseif {$type in $types_string_all} { if {[dict exists $types_string_short $type]} { set type [dict get $types_string_short $type] } $tree set $node type $type # No modifying operator for strings parsetypemod $tree $node if {$type eq {search} && [$tree get $node mand] eq {}} { parsewarning {search has no number} # set the same default that file(1) sets $tree set $node mand 100 } } elseif {$type in {default name use}} { $tree set $node type $type } elseif {$type in $types_notimplemented} { parseerror {type not implemented} } else { parseerror {unknown type} } } else { parseerror {no type} } } proc ::fileutil::magic::cfront::parsetypemod {tree node} { # For numeric types , $mod is a list of modifiers and $mand is either a # number or the empty string . variable typemodifiers variable numeric_modifier_allowed set type [$tree get $node type] if {[advance 1 char] ne {/}} { rewind 1 return } set res [dict create] while 1 { if {[advance 1 char] eq {/}} { continue } if {[string is space $char]} { break } if {[dict exists $typemodifiers $type] && $char in [dict get $typemodifiers $type]} { dict set res $char {} } elseif {$type in $numeric_modifier_allowed} { rewind 1 if {[catch {parseint $tree $node} mand]} { # Whatever it is, it isn't a number. Let the next parsing step # handle it . break } else { $tree set $node mand $mand ; # numeric modifier } } else { parseerror {bad modifier} } } $tree set $node mod [dict keys $res] } proc ::fileutil::magic::cfront::parsetypenummod {tree node} { variable typemap # For numeric types, $mod is an operator and $mand is a number set line [$tree get $node line] set type [$tree get $node type] set cursor [$tree get $node cursor] if {[regexp -start $cursor {\A([-&|^+*/%=])} $line match mod]} { advance [string length $match] $tree set $node mod $mod # {to do} {parse floats?} set mand [parseint $tree $node] ; # mod operand if {[info exists typemap($type)]} { lassign $typemap($type) dummy scan # the modifier for a numeric type is a number of the same # type binary scan [binary format $scan $mand] $scan mand } $tree set $node mand $mand } else { $tree set $node mod {} $tree set $node mand {} } } proc ::fileutil::magic::cfront::parsestringval {tree node} { variable floattestops variable inttestops variable stringtestops advance w1 char set val {} set nodetype [$tree get $node type] set line [$tree get $node line] while 1 { # break on whitespace or empty string if {[string is space $char] || $char eq {}} break switch $char [dict create \ \\ { advance 1 char if {[string is space $char]} { append val \\$char } else { # extra backslashes because of interaction with glob switch -glob -- $char { \\\\ { append val {\\} } \t { parsewarning {use \t instead of \<tab>} append val \\t } > - < - & - ^ - = - ! - ( - ) - . { if {$char in [list {*}$stringtestops \ {*}$floattestops {*}$inttestops]} { parsewarning {no need to escape operators} } append val $char } a - b - f - n - r - t - v { append val \\$char } x { set cursor [$tree get $node cursor] if {[regexp -start $cursor \ {\A([0-9A-Fa-f]{1,2})} $line match char2]} { advance [string length $match] append val \\x$char2 } else { parseerror {malformed \x escape sequence} } } [0-7] { set cursor [$tree get $node cursor] append val \\$char if {[regexp -start $cursor \ {\A([0-7]{1,2})} $line match char2]} { advance [string length $match] append val $char2 } } default { if {$nodetype eq {regex}} { if {$char ni {[ ] ( ) . * ? ^ $ | \{ \}}} { parsewarning [list {no need to escape}] } } elseif {[string is print $char]} { if {$char ni {< > & ^ = !}} { parsewarning [list {no need to escape}] } } append val [tclescape $char] } } } } default { append val [tclescape $char] } ] advance 1 char } $tree set $node val $val } proc ::fileutil::magic::cfront::parsetest {tree node} { variable floattestops variable inttestops variable stringtestops variable types_numeric_real variable types_numeric_all variable types_string variable types_verbatim variable typemap set type [$tree get $node type] if {$type in $types_verbatim} { parsetestverbatim $tree $node return } $tree set $node compinvert 0 set testinvert 0 set comp == advance w1 char if {$char eq {x}} { advance 1 char if {[string is space $char]} { $tree set $node testinvert 0 $tree set $node comp x $tree set $node val {} return } else { rewind 1 } } if {$type in $types_string} { while 1 { if {$char in $stringtestops} { if {$char eq {!}} { set testinvert 1 } else { set comp $char # Exclamation must precede any normal operator break } advance w1 char } else { rewind 1 break } } parsestringval $tree $node } elseif {$type in $types_numeric_all} { if {$type in $types_numeric_real} { set ops $floattestops set parsecmd parsefloat } else { set ops $inttestops set parsecmd parseint } while 1 { if {$char in $ops} { if {$char eq {~}} { $tree set $node compinvert 1 } elseif {$char eq {!}} { set testinvert 1 } else { set comp $char # Exclamation and tilde must precede any normal operator break } advance w1 char } else { rewind 1 break } } set val [$parsecmd $tree $node] set scan [lindex $typemap([$tree get $node type]) 1] # get value in binary form, then back to numeric # this avoids problems with sign, as both values are # [binary scan]-converted identically binary scan [binary format $scan $val] $scan val $tree set $node val $val } else { parseerror {don't know how to parse the test or this type} } switch $comp { = { set comp == } } # This facilitates Switch creation by [treegen1] if {$testinvert && ($comp eq {==})} { set comp != set testinvert 0 } $tree set $node testinvert $testinvert $tree set $node comp $comp } proc ::fileutil::magic::cfront::parsetestverbatim {tree node} { switch [$tree get $node type] { name { $tree set $node rel 1 } use { set cursor [$tree get $node cursor] # order matters in regular expression : longest match must come # first in parenthesized if {[regexp -start $cursor {\A\s*(?:\\\^|\^)} [$tree get $node line] match]} { advance [string length $match] $tree set $node iendian 1 } else { $tree set $node iendian 0 } } } parsestringval $tree $node } proc ::fileutil::magic::cfront::parseoffset {tree node} { # Offset parser. # Syntax: # ( ?&? number ?.[bslBSL]? ?[+-]? ?number? ) # This was all fine and dandy, but didn't do spaces where spaces might # exist between lexical elements in the wild, and ididn't do offset # operators #set n {([-+]?[0-9]+|[-+]?0x[0-9A-Fa-f]+)[UL]*} ##"\\((&?)(${n})((\\.\[bslBSL])?)()(\[+-]?)(${n}?)\\)" #set o \ # "^(&?)${n}((?:\\.\[bslBSL])?)(?:(\[-+*/%&|^])${n})?(?:(\[+-])(\\()?${n}\\)?)?$" ## | | | | | | | | ## 1 2 3 4 5 6 7 8 ## 1 2 3 4 5 6 7 8 #set ok [regexp $o $offset -> irel base type iop ioperand sign ind idx] variable offsetopts variable indir_typemap $tree set $node rel 0 ; # relative $tree set $node ind 0 ; # indirect $tree set $node ir 0 ; # indirect relative $tree set $node it {} ; # indir_type $tree set $node ioi 0 ; # indirect offset invert $tree set $node iir 0 ; # indirect indirect relative $tree set $node ioo + ; # indirect_offset_op $tree set $node io 0 ; # indirect offset advance w1 char if {$char eq {&}} { advance w1 char $tree set $node rel 1 } if {$char eq {(}} { $tree set $node ind 1 if {[advance w1] eq {&}} { $tree set $node ir 1 } else { rewind 1 } $tree set $node o [parseint $tree $node] # $char is used below if it's not "." if {[advance w1 char] in {. ,}} { advance w1 it if {[dict exists $indir_typemap $it]} { set it [ dict get $indir_typemap $it] if {$char eq {.}} { set it u$it } } else { parseerror {bad indirect offset type} } advance w1 char } else { set it long } $tree set $node it $it # The C implementation does this, so we will , too . if {$char eq {~}} { advance w1 char $tree set $node ioi 1 } if {$char in $offsetopts} { $tree set $node ioo $char if {[advance w1] in {(}} { $tree set $node iir 1 } else { rewind 1 } $tree set $node io [parseint $tree $node] if {[$tree get $node iir]} { if {[advance w1] ne {)}} { parseerror { expected closing parenthesis for indirect indirect offset offset } } } advance w1 char } if {$char ne {)}} { parseerror { expected close parenthesis for indirect offset } } } else { rewind 1 $tree set $node o [parseint $tree $node] } } proc ::fileutil::magic::cfront::parseoffsetmod {tree node} { advance w1 char if {$char eq {~}} { $tree set $node offset_invert 1 advance w1 char } else { $tree set $node offset_invert 0 } switch $char { + - - - * - / - % - & - | - ^ { $tree set $node offset_mod_op $char $tree set $node offset_mod [parseint $tree $node] } default { $tree set $node offset_mod_op {} $tree set $node offset_mod {} rewind 1 # no offset modifier } } } proc ::fileutil::magic::cfront::parsemsg {tree node} { advance w set line [$tree get $node line] set cursor [$tree get $node cursor] ##leave \b in the message for [emit] to parse #regexp -start $cursor {\A(\b|\\b)?(.*)$} $line match b line #if {$b ne {}} { # $tree set $node space 0 #} else { # $tree set $node space 1 #} set line [string range $line $cursor end] $tree set $node desc $line } # process a magic file proc ::fileutil::magic::cfront::process {tree file {maxlevel 10000}} { variable level ;# level of line variable linenum ;# line number set level 0 set linenum 0 set records {} set rejected 0 set script {} if {[$tree keyexists root files]} { set files [$tree get root files] } else { set files {} } set fileidx [llength $files] if {$file in $files} { return -code error [list {already processed file} $file] } lappend files $file $tree set root files $files $tree set root level -1 set node root ::fileutil::foreachLine line $file { incr linenum # Only trim the left side . White space on the the right side could be # part of an escape sequence , and trimming would munge it . set line [string trimleft $line] if {[string index $line 0] eq {#}} { continue ;# skip comments } elseif {$line eq {}} { continue ;# skip blank lines } else { # parse line if {[regexp {^\s*!:(\S+)\s*(.*?)\s*$} $line -> extname extdata]} { if {$rejected} { continue } if {$node eq {root}} { return -code error [list {malformed magic file}] } $tree set $node ext_$extname $extdata } else { # calculate the line's level set unlevel [string trimleft $line >] set level [expr {[string length $line] - [string length $unlevel]}] set line $unlevel if {$level > $maxlevel} { return -code continue "Skip - too high a level" } if {$level > 0} { if {$rejected} { continue } while {[$tree keyexists $node level] && [$tree get $node level] >= $level} { set node [$tree parent $node] } if {$level > [$tree get $node level]+1} { return -code error [ list {level more than one greater than parent level} \ file $file linenum $linenum line $line] } set node [$tree insert $node end] } else { set rejected 0 set node [$tree insert root end] set node0 $node } $tree set $node file $fileidx $tree set $node line $line $tree set $node linenum $linenum $tree set $node level $level if {[catch {parseline $tree $node} cres copts]} { set errorcode [dict get $copts -errorcode] if {[lindex $errorcode 0] eq {fumagic} && [ lindex $errorcode 1] eq {parse error}} { # don't delete the full node because the parts that # have been parsed so far might be useful #$tree delete $node0 $tree delete $node set rejected 1 puts stderr [list Rejected {bad parse}] puts stderr [dict get $copts -errorinfo] continue ;# skip erroring lines } else { return -options $copts $cres } } } } # collect some summaries ::fileutil::magic::cfront::Debug { variable types set types($type) [$tree get $node type] variable quals set quals($qual) [$tree get $node qual] } #puts $linenum level:$level offset:$offset type:$type #puts qual:$qual compare:$compare val:'$val' desc:'$desc' } } proc ::fileutil::magic::cfront::rewind len { upvar node node tree tree set cursor [$tree get $node cursor] incr cursor -$len $tree set $node cursor $cursor } proc ::fileutil::magic::cfront::tclescape char { if {[string is space $char] || $char in [ list \# \{ \} \[ \] \" \$ \; \n]} { append val \\ } append val $char return $val } proc ::fileutil::magic::cfront::tree {} { set tree [::struct::tree] $tree set root path "" $tree set root otype Root $tree set root type root $tree set root named {} $tree set root message "unknown" return $tree } # ### ### ### ######### ######### ######### ## Internal, debugging. if {!$::fileutil::magic::cfront::debug} { # This procedure definition is optimized out of using code by the # core bcc. It knows that neither argument checks are required, |
︙ | ︙ |
Changes to modules/fumagic/cgen.tcl.
︙ | ︙ | |||
25 26 27 28 29 30 31 | # ### ### ### ######### ######### ######### ## Requirements package require Tcl 8.4 package require fileutil::magic::rt ; # Runtime core, for Access to the typemap package require struct::list ; # Our data structures. | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # ### ### ### ######### ######### ######### ## Requirements package require Tcl 8.4 package require fileutil::magic::rt ; # Runtime core, for Access to the typemap package require struct::list ; # Our data structures. package provide fileutil::magic::cgen 1.3.0 # ### ### ### ######### ######### ######### ## Implementation namespace eval ::fileutil::magic { namespace export * } |
︙ | ︙ | |||
53 54 55 56 57 58 59 60 61 62 63 64 65 66 | namespace export 2tree treedump treegen # Assumption : the parser folds the test inversion operator into equality and # inequality operators . variable offsetskey { type o rel ind ir it ioi ioo iir io compinvert mod mand } } # Optimisations: # reorder tests according to expected or observed frequency this # conflicts with reduction in strength optimisations. | > > > > | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | namespace export 2tree treedump treegen # Assumption : the parser folds the test inversion operator into equality and # inequality operators . variable offsetskey { type o rel ind ir it ioi ioo iir io compinvert mod mand } variable indent {} variable indents {} variable innamed 0 } # Optimisations: # reorder tests according to expected or observed frequency this # conflicts with reduction in strength optimisations. |
︙ | ︙ | |||
87 88 89 90 91 92 93 94 95 96 97 98 99 100 | # # - String tests at same level over overlapping ranges can be # written as sub-string comparisons over the maximum range # this saves re-reading the same string from file. # # - common prefix strings will have to be guarded against, by # sorting string values, then sorting the tests in reverse length order. proc ::fileutil::magic::cgen::path {tree} { # Annotates the tree. In each node we store the path from the root # to this node, as list of nodes, with the current node the last # element. The root node is never stored in the path. $tree set root path {} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # # - String tests at same level over overlapping ranges can be # written as sub-string comparisons over the maximum range # this saves re-reading the same string from file. # # - common prefix strings will have to be guarded against, by # sorting string values, then sorting the tests in reverse length order. proc ::fileutil::magic::cgen::LessIndent {} { variable indent variable indents set size [expr {[string length $indent] - 1}] if {[dict exists $indents $size]} { set indent [dict get $indents $size] } else { set indent [string repeat \t $size] dict set indents $size $indent } return } proc ::fileutil::magic::cgen::MoreIndent {} { variable indent variable indents set size [expr {[string length $indent] + 1}] if {[dict exists $indents $size]} { set indent [dict get $indents $size] } else { set indent [string repeat \t $size] dict set indents $size $indent } return } proc ::fileutil::magic::cgen::path {tree} { # Annotates the tree. In each node we store the path from the root # to this node, as list of nodes, with the current node the last # element. The root node is never stored in the path. $tree set root path {} |
︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | } lappend path [$tree index $node] $tree set $node path $path foreach name {type} { set $name [$tree get $node $name] } # Recursively creates and annotates a node for the specified # tests, and its sub-tests (args). # generate a proc call type for the type, Numeric or String variable ::fileutil::magic::rt::typemap switch -glob -- $type { *byte* - *double* - *short* - *long* - *quad* - *date* { $tree set $node otype N } | > > > | < > > > > > > | 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 | } lappend path [$tree index $node] $tree set $node path $path foreach name {type} { set $name [$tree get $node $name] } puts stderr [list frlaalm [$tree getall $node]] # Recursively creates and annotates a node for the specified # tests, and its sub-tests (args). # generate a proc call type for the type, Numeric or String variable ::fileutil::magic::rt::typemap switch -glob -- $type { *byte* - *double* - *float* - *short* - *long* - *quad* - *date* { $tree set $node otype N } clear - search - regex - *string* { $tree set $node otype S } name { $tree set $node otype A } use { $tree set $node otype U } default { $tree set $node otype D } indirect { $tree set $node otype T } default { puts stderr "Unknown type: '$type'" $tree set $node otype Unknown } } # Stores the type determined above, and the arguments into |
︙ | ︙ | |||
170 171 172 173 174 175 176 | tree_el $tree $child } optNum $tree root #optStr $tree root puts stderr "Script contains [llength [$tree children root]] discriminators" path $tree | < < < < | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | tree_el $tree $child } optNum $tree root #optStr $tree root puts stderr "Script contains [llength [$tree children root]] discriminators" path $tree return $tree } proc ::fileutil::magic::cgen::isStr {tree node} { return [expr {"S" eq [$tree get $node otype]}] } |
︙ | ︙ | |||
246 247 248 249 250 251 252 | } proc ::fileutil::magic::cgen::isNum {tree node} { return [expr {"N" eq [$tree get $node otype]}] } proc ::fileutil::magic::cgen::switchNSort {tree n1 n2} { | > > > | > > | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | } proc ::fileutil::magic::cgen::isNum {tree node} { return [expr {"N" eq [$tree get $node otype]}] } proc ::fileutil::magic::cgen::switchNSort {tree n1 n2} { # deal with the fact that [lsort] barfs if the result is larger than 32 # bits set val1 [$tree get $n1 val] set val2 [$tree get $n2 val] expr {$val1 > $val2 ? 1 : $val1 < $val2 ? -1 : 0} } proc ::fileutil::magic::cgen::optNum {tree node} { variable offsetskey array set offsets {} # traverse each numeric element of this node's children, |
︙ | ︙ | |||
318 319 320 321 322 323 324 | $tree set $switch path $path set level [$tree get [$tree parent $switch] level] $tree set $switch level [expr {$level+1}] } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 | $tree set $switch path $path set level [$tree get [$tree parent $switch] level] $tree set $switch level [expr {$level+1}] } } # Useful when debugging proc ::fileutil::magic::cgen::stack {tree node} { set res {} set files [$tree get root files] while 1 { set s [dict create \ |
︙ | ︙ | |||
421 422 423 424 425 426 427 | append result " " C([$tree get $node comp]) } if {[$tree keyexists $node val]} { append result " " V([$tree get $node val]) } if {[$tree keyexists $node otype]} { | | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | append result " " C([$tree get $node comp]) } if {[$tree keyexists $node val]} { append result " " V([$tree get $node val]) } if {[$tree keyexists $node otype]} { append result " " [$tree get $node otype] } if {$depth == 1} { set msg [$tree get $node desc] set n $node while {($n != {}) && ($msg == "")} { set n [lindex [$tree children $n] 0] |
︙ | ︙ | |||
446 447 448 449 450 451 452 453 454 455 456 457 458 | #append result " <" [$tree getall $node] > append result \n } return $result } proc ::fileutil::magic::cgen::treegen {tree node} { variable ::fileutil::magic::rt::typemap set result {} set otype [$tree get $node otype] set level [$tree get $node level] | > > < < > > | | | | | | | | | | | | | > > | > > | > | < | | | < < < < < < | | | | < > > > > | | | | | < < | | | > > | > > > | | | > > | > > > > > > | | | | | | | | | | | | > > > > > > | > > > > > > > > > > > | < < < | < | > > | < > > | > | | | | < < < | > > | | | > > > > | | | > | | | > > | > | | | | | > | | | > | > > > > > > > | | > > > > | > > > > > > > > > > > > > | 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 | #append result " <" [$tree getall $node] > append result \n } return $result } proc ::fileutil::magic::cgen::treegen {tree node} { variable indent variable innamed variable ::fileutil::magic::rt::typemap set result {} set otype [$tree get $node otype] set level [$tree get $node level] # Generate code for each node per its type. switch $otype { A { incr innamed try { set file [$tree get $node file] set val [$tree get $node val] if {[dict exists named $file$val]} { return -code error [list {name already exists} $file $val] } set aresult {} foreach child [$tree children $node] { lappend aresult [treegen $tree $child] } set named [$tree get root named] dict set named $file $val [join $aresult \n] $tree set root named $named return } finally { incr innamed -1 } } U { set file [$tree get $node file] set val [$tree get $node val] # generateOffset is expanded via subsitution append result "${indent}U [list $file] [list $val] [ GenerateOffset $tree $node]\n" } N - S - D { set names {type mod mand testinvert compinvert comp val desc path} foreach name $names { set $name [$tree get $node $name] } set o [GenerateOffset $tree $node] if {$val eq {}} { # If the value is the empty string, armor it. Otherwise, it's # already been armored. set val [list $val] } switch $otype { N { set type [list N $type] # $type and $o are expanded via substitution append result "${indent}if \{\[$type $o [list $testinvert] [ list $compinvert] [list $mod] [list $mand] [ list $comp] $val\]\} \{\n" MoreIndent append result "${indent}>\n" } S { switch $comp { == {set comp eq} != {set comp ne} } set type [list S $type] append result "${indent}if \{\[$type $o [list $testinvert] [ list $mod] [list $mand] [list $comp] $val\]\} \{\n" MoreIndent append result "${indent}>\n" } D { set type [list D] append result "${indent}if \{\[$type $o]\} \{\n" MoreIndent append result "${indent}>\n" } } MoreIndent if {[$tree isleaf $node] && $desc ne {}} { append result "${indent}emit [list $desc]\n" } else { if {$desc ne {}} { append result "${indent}emit [list $desc]\n" } foreach child [$tree children $node] { append result [treegen $tree $child]\n } #append result "\nreturn \$result" } if {[$tree keyexists $node ext_mime]} { append result "${indent}mime [list [$tree get $node ext_mime]]\n" } if {[$tree keyexists $node ext_ext]} { append result "${indent}ext [list [$tree get $node ext_ext]]\n" } if {[$tree keyexists $node ext_strength]} { append result "${indent}strength [list [$tree get $node ext_strength]]\n" } LessIndent append result ${indent}<\n LessIndent append result ${indent}\}\n } T { set desc [$tree get $node desc] if {$desc ne {}} { append result "${indent}emit [list $desc]\n" } set o [GenerateOffset $tree $node] set mod [$tree get $node mod] append result "${indent}T $o [list $mod]\n" } Root { foreach child [$tree children $node] { lappend result [treegen $tree $child] if {[lindex $result end] eq {}} { set result [lreplace $result[set result {}] end end] } } } Switch { set names {o type compinvert mod mand} foreach name $names { set $name [$tree get $node $name] } set o [GenerateOffset $tree $node] set fetch Nv append fetch " $type $o [list $compinvert] [list $mod] [list $mand]" append result "${indent}switch \[$fetch\] \{\n" MoreIndent set scan [lindex $typemap($type) 1] foreach child [lsort -command [ list ::fileutil::magic::cgen::switchNSort $tree] [ $tree children $node]] { # See ::fileutil::magic::rt::rtscan if {$scan eq {me}} { set scan I } set val [$tree get $child val] if {[info exists lastval] && $lastval != $val} { LessIndent append result "${indent}\}\n" } if {![info exists lastval] || $lastval != $val} { append result "${indent}$val \{\n" MoreIndent } append result "${indent}>\n" MoreIndent set desc [$tree get $child desc] # emit, mime, and ext come first so that they are # picked up when child nodes produce results if {$desc ne {}} { append result "${indent}emit [list $desc]\n" } if {[$tree keyexists $child ext_mime]} { append result "${indent}mime [list [ $tree get $child ext_mime]]\n" } if {[$tree keyexists $child ext_ext]} { append result "${indent}ext [list [ $tree get $child ext_ext]]\n" } if {![$tree isleaf $child]} { foreach grandchild [$tree children $child] { append result [treegen $tree $grandchild]\n } } LessIndent append result "${indent}<\n" set lastval $val } LessIndent append result "${indent}\}\n" LessIndent append result "${indent}\}\n" } } return $result } proc ::fileutil::magic::cgen::GenerateOffset {tree node} { # Examples: # direct absolute: 45 -> 45 # direct relative: &45 -> [R 45] # indirect absolute: (45.s+1) -> [I 45 s + 0 1] # indirect absolute (indirect offset): (45.s+(1)) -> [I 45 s + 1 1] # relative indirect absolute: &(45.s+1) -> [R [I 45 s + 0 1]] # relative indirect absolute (indirect offset): &(45.s+(1)) -> [R [I 45 s + 1 1]] # indirect relative: (&45.s+1) -> [I [R 45] s op 0 1] # relative indirect relative: &(&45.s+1) -> [R [I [R 45] s + 0 1]] # relative indirect relative: &(&45.s+(1)) -> [R [I [R 45] s + 1 1]] variable innamed foreach v {o rel ind ir it ioi iir ioo io} { set $v [$tree get $node $v] } #foreach v {ind rel base itype iop ioperand iindir idelta} { # set $v [$tree get $node $v] #} if {$ind} { if {$ir} {set o "\[R $o]"} set o "\[I $o [list $it] [list $ioi] [list $ioo] [list $iir] [list $io]\]" } # spec # named instance direct offsets are relative to the offset of the # previous matched entry if {$innamed} { set o "\[O $o]" } if {$rel} { set o "\[R $o\]" } return $o } # ### ### ### ######### ######### ######### ## Ready for use. # EOF |
Changes to modules/fumagic/filetypes.tcl.
more than 10,000 changes
Changes to modules/fumagic/filetypes.test.
︙ | ︙ | |||
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 | } # ------------------------------------------------------------------------- # Now the package specific tests.... set path [makeFile {} bogus] removeFile bogus test fumagic.filetype-1.1 {test file non-existance} { set res [catch {fileutil::magic::filetype $path} msg] list $res $msg } [list 1 "file not found: \"$path\""] test fumagic.filetype-1.2 {test file directory} { set f [makeDirectory fileTypeTest] set res [catch {fileutil::magic::filetype $f} msg] regsub {file[0-9]+} $msg {fileXXX} msg removeDirectory fileTypeTest list $res $msg } {0 {directory application/x-directory {}}} test fumagic.filetype-1.3 {test file empty} { set f [makeEmptyFile] set res [catch {fileutil::magic::filetype $f} msg] removeEmptyFile list $res $msg | > > > | > | > | > | > > > > > > | | > | > | > | < | > | > > > | > | > > | > | > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | } # ------------------------------------------------------------------------- # Now the package specific tests.... set path [makeFile {} bogus] removeFile bogus test fumagic.filetype-1.1 {test file non-existance} { set res [catch {fileutil::magic::filetype $path} msg] list $res $msg } [list 1 "file not found: \"$path\""] test fumagic.filetype-1.2 {test file directory} { set f [makeDirectory fileTypeTest] set res [catch {fileutil::magic::filetype $f} msg] regsub {file[0-9]+} $msg {fileXXX} msg removeDirectory fileTypeTest list $res $msg } {0 {directory application/x-directory {}}} test fumagic.filetype-1.3 {test file empty} { set f [makeEmptyFile] set res [catch {fileutil::magic::filetype $f} msg] removeEmptyFile list $res $msg } {0 {empty {} {}}} test fumagic.filetype-1.4 {test simple binary} { set f [makeBinFile] set res [catch {fileutil::magic::filetype $f} msg] removeBinFile list $res $msg } {0 {binary {} {}}} test fumagic.filetype-1.5 {test elf executable} { set f [makeElfFile] set res [catch {fileutil::magic::filetype $f} msg] removeElfFile list $res $msg } {0 {{ELF 32-bit LSB executable {*unknown arch 0x0*} SYSV} {application x-executable} {}}} test fumagic.filetype-1.6 {test simple text} { set f [makeTextFile] set res [catch {fileutil::magic::filetype $f} msg] removeTextFile list $res $msg } {0 {text {} {}}} test fumagic.filetype-1.7 {test script file} { set f [makeScriptFile] set res [catch {fileutil::magic::filetype $f} msg] removeScriptFile list $res $msg } {0 {{a {/bin/tclsh script text executable}} {} {}}} test fumagic.filetype-1.8 {test html text} { set f [makeHtmlFile] set res [catch {fileutil::magic::filetype $f} msg] removeHtmlFile list $res $msg } {0 {{{HTML document text}} {text html} {}}} test fumagic.filetype-1.9 {test xml text} { set f [makeXmlFile] set res [catch {fileutil::magic::filetype $f} msg] removeXmlFile list $res $msg } {0 {{XML {1.0 document text}} {text xml} {}}} test fumagic.filetype-1.10 {test xml with dtd text} { set f [makeXmlDTDFile] set res [catch {fileutil::magic::filetype $f} msg] removeXmlDTDFile list $res $msg } {0 {{XML {1.0 document text}} {text xml} {}}} test fumagic.filetype-1.11 { test PGP message. Their are multiple matches, and the longest match should carry greater weight, and thus be the one returned. If the match is "PGP armored data message", this isn't happening. } { set f [makePGPFile] set res [catch {fileutil::magic::filetype $f} msg] removePGPFile list $res $msg } {0 {{{PGP message}} {application pgp} {}}} test fumagic.filetype-1.12.0 {test binary graphic jpeg} { set f [makeJpegFile] set res [catch {fileutil::magic::filetype $f} msg] removeJpegFile list $res $msg } {0 {{{JPEG image data} {JFIF standard 1.02} {resolution DPI} {density 300x316} {segment length 16}} {image jpeg} {jpeg jpg jpe jfif}}} #the result should actually be 128x112, but current magic files indicate "byte" instead of "ubyte" test fumagic.filetype-1.12.1 {test binary graphic jpeg} { set f [makeJpeg2File] set res [catch {fileutil::magic::filetype $f} msg] removeJpeg2File list $res $msg } {0 {{{JPEG image data} {JFIF standard 1.02} {resolution DPI} {density 300x316} {segment length 16} {thumbnail -128x112}} {image jpeg} {jpeg jpg jpe jfif}}} test fumagic.filetype-1.13 {test binary graphic gif} { set f [makeGifFile] set res [catch {fileutil::magic::filetype $f} msg] removeGifFile list $res $msg } {0 {{{GIF image data} {version 89a} {43 x} 64} {image gif} {}}} test fumagic.filetype-1.14 {test binary graphic png} { set f [makePngFile] set res [catch {fileutil::magic::filetype $f} msg] removePngFile list $res $msg } {0 {{{PNG image data} {0 x} 0 0-bit} {image png} {}}} #{To do} {implement a "wild guess" mode} #test fumagic.filetype-1.14.1 {test binary graphic png} { # set f [makePngFile] # set res [catch {fileutil::magic::filetype $f} msg] # removePngFile # list $res $msg #} {0 {PNG image data, CORRUPTED, PNG image data, CORRUPTED}} test fumagic.filetype-1.15 {test binary graphic tiff} { set f [makeTiffFile] set res [catch {fileutil::magic::filetype $f} msg] removeTiffFile list $res $msg } {0 {{{TIFF image data} big-endian direntries=0} {image tiff} {}}} test fumagic.filetype-1.16 {test binary pdf} { set f [makePdfFile] set res [catch {fileutil::magic::filetype $f} msg] removePdfFile list $res $msg } {0 {{{PDF document} {version 1.2}} {application pdf} {}}} test fumagic.filetype-1.17 {test text ps} { set f [makePSFile] set res [catch {fileutil::magic::filetype $f} msg] removePSFile list $res $msg } {0 {{{PostScript document text}} {application postscript} {}}} test fumagic.filetype-1.18 {test text eps} { set f [makeEPSFile] set res [catch {fileutil::magic::filetype $f} msg] removeEPSFile list $res $msg } {0 {{{PostScript document text}} {application postscript} {}}} test fumagic.filetype-1.19 {test binary gravity_wave_data_frame} { set f [makeIgwdFile] set res [catch {fileutil::magic::filetype $f} msg] removeIgwdFile list $res $msg } {0 {binary {} {}}} test fumagic.filetype-1.20 {test binary compressed bzip} { set f [makeBzipFile] set res [catch {fileutil::magic::filetype $f} msg] removeBzipFile list $res $msg } {0 {{{bzip2 compressed data} {block size = 900k}} {application x-bzip2} {}}} test fumagic.filetype-1.21 {test binary compressed gzip} { set f [makeGzipFile] set res [catch {fileutil::magic::filetype $f} msg] removeGzipFile list $res $msg } {0 {{{gzip compressed data} {reserved method} ASCII {original size 0}} {application x-gzip} {}}} test fumagic.filetype-1.22 {test pstring} { set f [makeWsdlFile] set res [catch {fileutil::magic::filetype $f} msg] removeWsdlFile list $res $msg } {0 {{{PHP WSDL cache} {version 0x03} {created 7} uri hello source {some source} target_ns {and a target}} {} {}}} test fumagic.filetype-1.23 {regular expressions} { set f [makeCSourceFile] set res [catch {fileutil::magic::filetype $f} msg] removeCSourceFile list $res $msg } {0 {{{C source text}} {text x-c} {}}} # XZ is the one format whose magic record is of type "ustring" test fumagic.filetype-1.24 {ustring} { set f [makeXzFile] set res [catch {fileutil::magic::filetype $f} msg] removeXzFile list $res $msg } {0 {{{XZ compressed data}} {application x-xz} {}}} test fumagic.filetype-1.25 { tests negative relative offsets } { set f [makePdf2File] set res [catch {fileutil::magic::filetype $f} msg] removePdf2File list $res $msg } {0 {{{PDF document} {version 1.3}} {application pdf} {}}} test fumagic.filetype-1.25.1 { matches and strengths } { set f [makePdf2File] set chan [open $f] set matches {} try { file stat $f stats set finfo [array get stats] dict set finfo name $f set coro [coroutine [info cmdcount] \ ::fileutil::magic::rt::new $finfo $chan \ $::fileutil::magic::filetype::named [ list [namespace which ::fileutil::magic::filetype::analyze]]] set class [$coro] while 1 { lassign [$coro] weight result mimetype ext dict update matches $weight weight { lappend weight [list $result $mimetype $ext] } } } finally { close $chan } removePdf2File return $matches } [list \ 5.0 [ list [ list [ list {tar archive V7} type {} \ %PDF-1.3 {mode 5} {uid ndobj} {gid xref} {size 870 00000 n} {seconds xref} {linkname xref} comment ] {application x-tar} tar] ] \ 66.0 {{{{PDF document} {version 1.3}} {application pdf} {}} {{{PDF document} {version 1.3}} {application pdf} {}}}] test fumagic.filetype-1.26 { Tests comparisons against the empty string when a file is malformed or missing data at specified offsets. } { set f [makePeFile] set res [catch {fileutil::magic::filetype $f} msg] removePeFile list $res $msg } {0 {{{MS-DOS executable}} {application x-dosexec} {}}} test fumagic.filetype-1.27 { Tests indirect offsets, as well as the "default" test type. } { set f [makePe2File] set res [catch {fileutil::magic::filetype $f} msg] removePe2File list $res $msg } {0 {{{PE32 executable} {Unknown PE signature} 0x10ba GUI {Intel 80386} {for MS Windows}} {application x-dosexec} {}}} if 0 { to do ebml and webm both have a belong at 440786851 make sure this is handled correctly } test fumagic.filetype-1.28 { Tests the "indirect" type and typed interpretation of values to be AND'ed with a numeric value. } { set f [makeMp3File] set res [catch {fileutil::magic::filetype $f} msg] removePeFile list $res $msg } {0 {{{Audio file with ID3 version 2.3.0} contains {MPEG ADTS} {layer III} v1 {128 kbps} {44.1 kHz} JntStereo} {audio mpeg} {}}} testsuiteCleanup return |
Changes to modules/fumagic/fumagic.testsupport.
︙ | ︙ | |||
36 37 38 39 40 41 42 | Bin "\u0000" \ Elf [cat "\x7F" "ELF" "\x01\x01\x01\x00\x00" "\x00\x00\x00\x00\x00\x00\x00" "\x02\x00"] \ Bzip "BZh91AY&SY\x01\x01\x01\x00\x00" \ Gzip "\x1f\x8b\x01\x01\x01\x00\x00" \ Jpeg [cat "\xFF\xD8\xFF\xE0\x00\x10JFIF" "\x00\x01\x02\x01\x01\x2c\x01\x3c"] \ Jpeg2 [cat "\xFF\xD8\xFF\xE0\x00\x10JFIF" "\x00\x01\x02\x01\x01\x2c\x01\x3c\x80\x70"] \ Gif "GIF89a\x2b\x00\x40\x00\xf7\xff\x00" \ | > > > | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | Bin "\u0000" \ Elf [cat "\x7F" "ELF" "\x01\x01\x01\x00\x00" "\x00\x00\x00\x00\x00\x00\x00" "\x02\x00"] \ Bzip "BZh91AY&SY\x01\x01\x01\x00\x00" \ Gzip "\x1f\x8b\x01\x01\x01\x00\x00" \ Jpeg [cat "\xFF\xD8\xFF\xE0\x00\x10JFIF" "\x00\x01\x02\x01\x01\x2c\x01\x3c"] \ Jpeg2 [cat "\xFF\xD8\xFF\xE0\x00\x10JFIF" "\x00\x01\x02\x01\x01\x2c\x01\x3c\x80\x70"] \ Gif "GIF89a\x2b\x00\x40\x00\xf7\xff\x00" \ Mp3 [binary format Hu* [join [string trim { 4944 3303 0000 0000 0000 fffb 9240 }] {}]] \ Png "\x89PNG\x0D\x0A\x1A\x0A\x00\x00\x00\x0DIHDR" \ PngMalformed "\x89PNG\x00\x01\x02\x01\x01\x2c" \ Tiff "MM\x00\*\x00\x01\x02\x01\x01\x2c" \ Pdf "%PDF-1.2 \x00\x01\x02\x01\x01\x2c" \ Pdf2 {%PDF-1.3 %âãÏÓ 25 0 obj << /Linearized 1 /O 29 /H [ 1948 443 ] /L 64573 /E 41907 /N 3 /T 63955 >> endobj xref 25 67 0000000016 00000 n 0000001687 00000 n 0000001800 00000 n |
︙ | ︙ |
Changes to modules/fumagic/pkgIndex.tcl.
1 2 3 4 5 6 | if {![package vsatisfies [package provide Tcl] 8.6]} {return} # Recognizers package ifneeded fileutil::magic::filetype 2.0 [list source [file join $dir filetypes.tcl]] # Runtime | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | if {![package vsatisfies [package provide Tcl] 8.6]} {return} # Recognizers package ifneeded fileutil::magic::filetype 2.0 [list source [file join $dir filetypes.tcl]] # Runtime package ifneeded fileutil::magic::rt 3.0 [list source [file join $dir rtcore.tcl]] # Compiler packages package ifneeded fileutil::magic::cgen 1.3.0 [list source [file join $dir cgen.tcl]] package ifneeded fileutil::magic::cfront 1.3.0 [list source [file join $dir cfront.tcl]] |
Changes to modules/fumagic/rtcore.man.
︙ | ︙ | |||
15 16 17 18 19 20 21 | [require Tcl 8.5] [require fileutil::magic::rt [opt [vset VERSION]]] [description] [para] This package provides the runtime core for file type recognition engines written in pure Tcl and is thus used by all other packages in | < < < | > < | < < | < < | < < < < < < | | < > < < > > > | < < > > < < < < < < < < < < < < < < < < < < < < < < < > > < < < < < | > | | < > < > > | < < < < < > > < < < < < < | > < < > > | < | | | < < < < | | < < < < | < < < < | < < < < < < < < | | < < < < | < > < | > | < < < < | | 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 | [require Tcl 8.5] [require fileutil::magic::rt [opt [vset VERSION]]] [description] [para] This package provides the runtime core for file type recognition engines written in pure Tcl and is thus used by all other packages in this module such as [package fileutil::magic::filetype] and the two compiler packages [package fileutil::magic::cgen] and [package fileutil::magic::cfront]. [section COMMANDS] [list_begin definitions] [call [cmd ::fileutil::magic::rt::>]] Increment the level and perform related housekeeping [call [cmd ::fileutil::magic::rt::<]] Decrement the level and perform related housekeeping [call [cmd ::fileutil::magic::rt::new] [arg chan] [arg named] [arg analyze]] Create a new command which returns one description of the file each time it is called, and a code of [arg break] when there are no more descriptions. [arg chan] is the channel containing the data to describe. The channel configuration is then managed as needed. [arg named] is a dictionary of named tests, as generated by [cmd fileutil::magic::cfront::compile]. [arg test] is a command prefix for a routine composed of the list of commands as returned by [cmd fileutil::magic::cfront::compile]. [call [cmd ::fileutil::magic::rt::file_start] [arg name]] This command marks the start of a magic file when debugging. It returns the empty string as its result. [call [cmd ::fileutil::magic::rt::emit] [arg msg]] This command adds the text [arg msg] to the result buffer. The message may contain the following special character sequences. They will be replaced with buffered values before the message is added to the result. The command returns the empty string as its result. [list_begin definitions] [def [const \\b]] This sequence is removed [def [const %s]] Replaced with the last buffered string value. [def [const %ld]] Replaced with the last buffered numeric value. [def [const %d]] See above. [def [const {${x:...?...}}]] Substitute one string if the file is executable, and another string otherwise. [list_end] [call [cmd ::fileutil::magic::rt::O] [arg where]] Produce an offset from [arg where], relative to the cursor one level up. [comment [call [cmd ::fileutil::magic::rt::R] [arg where]]] Produce an offset from [arg where], relative to the offset one level up. [call [cmd ::fileutil::magic::rt::Nv] [arg type] [arg offset] [ arg compinvert] [arg comp] [arg expected]] A limited form of [cmd ::fileutile::magic::rt::N] that only checks for equality and can't be told to invert the test. [call [cmd ::fileutil::magic::rt::N] [arg type] [arg offset] [arg testinvert] [ arg compinvert] [arg mod] [arg mand] [arg comp] [arg expected]] Fetch the numeric value with [arg type] from the absolute location [arg offset], compare it with [arg expected] using [arg comp] as the comparision operator, and returns the result. [para] The argument [arg comp] must be one of Tcl's comparison operators. [example { <comp> <fetched-and-masked-value> <comp> <expected> }] [para] The special comparison operator [const x] signals that no comparison should be done, or, in other words, that the fetched value will always match [arg val]. [call [cmd ::fileutil::magic::rt::S] [arg type] [arg offset] [arg testinvert] [ arg mod] [arg mand] [arg comp] [arg val]] Like [cmd ::fileutil::magic::rt::N] except that it fetches and compares string types , not numeric data. [call [cmd ::fileutil::magic::rt::L] [arg newlevel]] Sets the current level in the calling context to [arg newlevel]. The command returns the empty string as its result. [call [cmd ::fileutil::magic::rt::I] [arg offset] [arg it] [arg ioi] [arg ioo] [ arg iir] [arg io]] Calculates an offset based on an initial offset and the provided modifiers. [call [cmd ::fileutil::magic::rt::R] [arg offset]] Given an initial offset, calculates an offset relative to the cursor at the next level up. The cursor is the position in the data one character after the data extracted from the file one level up. [para] [call [cmd ::fileutil::magic::rt::U] [arg fileindex] [arg name]] Add a level and use a named test script. [list_end] [section {NUMERIC TYPES}] [list_begin definitions] [def [const byte]] 8-bit integer |
︙ | ︙ |
Changes to modules/fumagic/rtcore.tcl.
1 2 3 4 | # rtcore.tcl -- # # Runtime core for file type recognition engines written in pure Tcl. # | < > | | | < > | | < | > | < > > | > > > > > | | > > > > > > | > > > > > > > > > > > > > > > > > > > > > | | | | | | < < | | < < < < < < | < < < < < < | > > > > | > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | | > | | | < < < < | < < < < < | < < | < < < | < < < < < < < < < < < < > > > > > > > > > > > > > > | > > > | > > > | | > > > > | > > > > | > | > > > | > > > | > > > > > > | | > > | > > | > > > > > > > > > > > > > > > > | | > > > > > | > > > > > > > > > > > > > > | | | > > < < < < | | | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | # rtcore.tcl -- # # Runtime core for file type recognition engines written in pure Tcl. # # Copyright (c) 2004-2005 Colin McCormack <[email protected]> # Copyright (c) 2005 Andreas Kupries <[email protected]> # Copyright (c) 2016-2018 Poor Yorick <[email protected]> # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: rtcore.tcl,v 1.5 2005/09/28 04:51:19 andreas_kupries Exp $ ##### # # "mime type recognition in pure tcl" # http://wiki.tcl.tk/12526 # # Tcl code harvested on: 10 Feb 2005, 04:06 GMT # Wiki page last updated: ??? # ##### # TODO # Required Functionality # implement full offset language} # done # # by pooryorick # # time {2016 06} # # # implement pstring (pascal string) # done # # by pooryorick # # time {2016 06} #} # # implement regex form # done # # by pooryorick # # time {2016 06} # # # implement string qualifiers # done # # by pooryorick # # time {2016 06} # # implement correct handling of date types # # finish implementing the indirect type} # done # # by pooryorick # # 2018 08 # # Maybe distinguish between binary and text tests, like file(n) # # done # # by pooryorick # # 2018 08 # # process and use strength directives # # done # # by pooryorick # # 2018 08 # # handle the "indirect" type # # done # # by pooryorick # # 2018 08 # # # } #} # ### ### ### ######### ######### ######### ## Requirements package require Tcl 8.5 # ### ### ### ######### ######### ######### ## Implementation namespace eval ::fileutil::magic::rt { # Configuration flag. (De)activate debugging output. # This is done during initialization. # Changes at runtime have no effect. variable debug 0 # The maximum size of a substring to inspect from the file in question variable maxstring 64 # The maximum length of any %s substitution in a resulting description is variable maxpstring 64 variable regexdefaultlen 4096 # [*] The vast majority of magic strings are in the first 4k of the file. # Export APIs (full public, recognizer public) namespace export file_start result namespace export emit ext mime new offset strength \ D Nv N O S Nvx Nx Sx L R T I U < > namespace eval _ {} } # ### ### ### ######### ######### ######### ## Public API, general use. proc ::fileutil::magic::rt::> {} { upvar #1 cursors cursors depth depth found found \ level level lfound lfound strengths strengths \ typematch typematch useful useful virtual virtual set prevlevel $level incr level incr depth set cursors($level) $cursors($prevlevel) set strengths($level) 0 set useful($level) 0 set virtual($level) $virtual($prevlevel) set found 0 dict set lfound $level 0 return } proc ::fileutil::magic::rt::< {} { upvar #1 class class ext ext found found level level mime mime \ result result strengths strengths typematch typematch useful useful if {$level == 1 && [llength $result]} { set leveln $level set weight 0 while {$leveln >= 0} { set weight [ expr {$weight + $useful($leveln) + $strengths($leveln) + $typematch($leveln)}] incr leveln -1 } foreach item $result[set result {}] { set item [lmap {-> x ->} [regexp -all -inline \ {(.+?)([[:punct:]][[:space:]]+|[:,+]*$)} $item[set item {}]] { regsub {"(.*)"} $x {\1} x regsub {'(.*)'} $x {\1} x regsub {\((.*)\)} $x {\1} x regsub {\{(.*)\}} $x {\1} x regsub {<(.*)>} $x {\1} x regsub {\[(.*)\]} $x {\1} x regsub {[[:space:]][[:space:]]+} $x { } x string trim $x }] lappend result {*}$item } yield [list $weight $result $mime $ext] set result {} } # $useful holds weight of the match at each level, Each weight is # basically length of the match. set useful($level) 0 set strengths($level) 0 incr level -1 if {$level == 0} { set ext {} set found 0 set mime {} set depth 0 } } proc ::fileutil::magic::rt::classify {data} { set bin_rx {[\x00-\x08\x0b\x0e-\x1f]} if {[regexp $bin_rx $data] } { return binary } else { return text } } proc ::fileutil::magic::rt::executable {} { upvar #1 finfo finfo if {![dict exists $finfo mode]} { return 0 } expr {([dict get $finfo mode] & 0o111) > 0} } proc ::fileutil::magic::rt::ext value { upvar #1 ext ext set ext [split $value /] } # mark the start of a magic file in debugging proc ::fileutil::magic::rt::file_start {name} { ::fileutil::magic::rt::Debug {puts stderr "File: $name"} } proc ::fileutil::magic::rt::message msg { upvar #1 finfo finfo set ranges [regexp -all -inline -indices {\$\{([^\}]*)\}} $msg] foreach {orange irange} $ranges { lassign $irange first last set sub [string range $msg $first $last] if {[regexp {^x\?([^:]*?):(.*)$} $sub -> tmsg fmsg]} { set part [expr {[executable] ? $tmsg : $fmsg}] set msg [string replace $msg[set line {}] {*}$orange $part] } else { parseerror error [list {unrecognized variable in description}] } } return $msg } proc ::fileutil::magic::rt::mime value { upvar #1 mime mime set mime [split [message $value] /] } proc ::fileutil::magic::rt::new {finfo chan named tests} { coroutine _::[info cmdcount] [list [ namespace which coro]] $finfo $chan $named $tests } # level #1 of a coroutine proc ::fileutil::magic::rt::coro {finfo chan named tests} { array set cache {} ; # Cache of fetched and decoded numeric ; # values. ::fconfigure $chan -translation binary # fill the string cache set strbuf [::read $chan 4096] ; # Input cache [*]. set class [classify $strbuf] ; # text or binary # clear the fetch cache catch {unset cache} array set cache {} set depth 0 ; # depth of the current branch set ext {} set extracted {} ; # The value extracted for inspection set found 1 ; # Whether the last test produced a match set level 0 set lfound {} ; # For each level, whether a match was found dict set lfound 0 1 set mime {} set result {} ; # The accumulated recognition result that is ; # in progress. array unset cursors ; # the offset just after the last matching bytes, ; # per nesting level. array unset strengths ; #strengths at each level set virtual(0) 0 ; # the virtual start of the file at each level set strengths(0) 0 set typematch(0) 0 yield [info coroutine] yield $class if {[string length $strbuf] == 0} { yield [list 0 empty {} {}] } else { {*}$tests } rename [info coroutine] {} return -code break } proc ::fileutil::magic::rt::strength {expr} { upvar #1 level level strengths strengths upvar 0 strengths($level) strength # this expr must not be braced set strength [expr double($strength) $expr] } proc ::fileutil::magic::rt::use {named file name} { if [dict exists $named $file $name] { set script [dict get $named $file $name] } else { dict for {file1 val} $named { if {[dict exists $val $name]} { set script [dict get $val $name] break } } } if {![info exists script]} { return -code error [list {name not found} $file $name] } return $script } # ### ### ### ######### ######### ######### ## Public API, for use by a recognizer. # emit a description proc ::fileutil::magic::rt::emit msg { upvar #1 extracted extracted found found level level lfound lfound \ result result variable maxpstring set found 1 dict set lfound $level 1 #set map [list \ # \\b "" \ # %c [apply {extracted { # if {[catch {format %c $extracted} result]} { # return {} # } |
︙ | ︙ | |||
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | for {set i 0} {$i < $count} {incr i} { lappend arguments $extracted2 } catch {set msg [format $msg {*}$arguments]} # Assumption: [regexp] leaves $msg untouched if it fails regexp {\A(\b|\\b)?(.*)$} $msg match b msg if {$b ne {} && [llength $result]} { lset result end [lindex $result end]$msg } else { lappend result $msg } return } | > > > | > > > > > > > > < < < < | < | | | | < > | > | < < | < < < | < | | < | > | | < < | > > > > | > | | > | > > > > | | < < < < < < < < < | | 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 | for {set i 0} {$i < $count} {incr i} { lappend arguments $extracted2 } catch {set msg [format $msg {*}$arguments]} # Assumption: [regexp] leaves $msg untouched if it fails regexp {\A(\b|\\b)?(.*)$} $msg match b msg set msg [message $msg[set msg {}]] if {$b ne {} && [llength $result]} { lset result end [lindex $result end]$msg } else { lappend result $msg } return } proc ::fileutil::magic::rt::D offset { upvar #1 found found expr {!$found} } proc ::fileutil::magic::rt::I {offset it ioi ioo iir io} { # Handling of base locations specified indirectly through the # contents of the inspected file. upvar #1 level level variable typemap foreach {size scan} $typemap($it) break set offset [Fetch $offset $size $scan] if {[catch {expr {$offset + 0}}]} { return [expr {-1 * 2 ** 128}] } if {$ioi && ![catch {$offset + 0}]} { set offset [expr {~$offset}] } if {$iir} { set io [Fetch [expr {$offset + $io}] $size $scan] } if {$ioo ne {}} { # no bracing this expression set offset [expr $offset $ioo $io] } return $offset } proc ::fileutil::magic::rt::L newlevel { upvar #1 level level set level $newlevel # Regenerate level information in the calling context. return } # Numeric - get bytes of $type at $offset and $compare to $val # qual might be a mask proc ::fileutil::magic::rt::N { type offset testinvert compinvert mod mand comp val} { upvar #1 class class cursors cursors extracted extracted level level \ typematch typematch useful useful variable typemap # unpack the type characteristics foreach {size scan} $typemap($type) break # fetch the numeric field set extracted [Fetch $offset $size $scan] if {$extracted eq {}} { # Rules like the following, from the jpeg file, imply that # in the absence of an extracted value, a numerical value of # 0 should be used # From jpeg: ## Next, show thumbnail info, if it exists: #>>18 byte !0 \b, thumbnail %dx # # pyk 2018-08-16: # Not necessarily. The failure to extract might cause the rule to # be skipped. Consider doing something different here. set extracted 0 } # Would moving this before the fetch be an optimisation ? The # tradeoff is that we give up filling the cache, and it is unclear # how often that value would be used. -- Profile! if {$comp eq {x}} { set useful($level) 0 # anything matches - don't care if {$testinvert} { return 0 } else { return 1 } } if {$compinvert && $extracted ne {}} { set extracted [expr -$extracted] } # perform comparison if {$mod ne {}} { # there's a mask to be applied set extracted [expr $extracted $mod $mand] } |
︙ | ︙ | |||
369 370 371 372 373 374 375 | } default { #Should never reach this return -code error [list {unknown comparison operator} $comp] } } # Do this last to minimize shimmering | | > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > > > > > > > | > > > > > > > > > > > > > | > > < < | > > | | | | | > > | > > > | > | | > | | | | | > > | > > > > < > | | 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 | } default { #Should never reach this return -code error [list {unknown comparison operator} $comp] } } # Do this last to minimize shimmering set useful($level) [string length $extracted] if {$class eq {binary}} { set typematch($level) 1 } else { set typematch($level) 0 } ::fileutil::magic::rt::Debug { puts stderr "numeric $type: $val $t$comp $extracted / $mod - $c" } if {$testinvert} { set c [expr {!$c}] return $c } else { return $c } } proc ::fileutil::magic::rt::Nv {type offset compinvert mod mand} { upvar #1 class class cursors cursors extracted extracted level level \ offsets offsets useful useful variable typemap set offsets($level) $offset # unpack the type characteristics foreach {size scan} $typemap($type) break # fetch the numeric field from the file set extracted [Fetch $offset $size $scan] if {$compinvert && $extracted ne {}} { set extracted [expr ~$extracted] } if {$mod ne {} && $extracted ne {}} { # there's a mask to be applied set extracted [expr $extracted $mod $mand] } if {$class eq {binary}} { set typematch($level) 1 } else { set typematch($level) 0 } ::fileutil::magic::rt::Debug {puts stderr "NV $type $offset $mod: $extracted"} set useful($level) [string length $extracted] return $extracted } proc ::fileutil::magic::rt::O offset { # Handling of offset locations specified relative to the offset # last field one level up. upvar #1 offsets offsets level level upvar 0 offsets([expr {$level -1}]) base return [expr {$base + $offset}] } proc ::fileutil::magic::rt::R offset { # Handling of offset locations specified relative to the cursor one level # up. upvar #1 cursors cursors level level upvar 0 cursors([expr {$level -1}]) cursor return [expr {$cursor + $offset}] } proc ::fileutil::magic::rt::S {type offset testinvert mod mand comp val} { upvar #1 cursors cursors extracted extracted level level \ lfound lfound useful useful variable maxstring variable regexdefaultlen upvar 0 cursors($level) cursor useful($level) used set cursor $offset # $compinvert is currently ignored for strings switch $type { pstring { set ptype B set vincluded 0 # The last pstring type specifier wins foreach item $mod { if {$item eq {J}} { set vincluded 1 } else { set ptype $item } } lassign [dict get {B {b 1} H {S 2} h {s 2} L {I 4} l {i 4}} $ptype] scan slength set length [GetString $offset $slength] incr offset $slength incr cursor $slength set scanu ${scan}u if {[binary scan $length $scanu length2]} { if {$vincluded} { set length2 [expr {$length2 - $slength}] } set extracted [GetString $offset $length2] incr cursor [string length $extracted] array get cursors]] set c [Smatch $val $comp $extracted $mod] } else { set c 0 } } regex { if {$mand eq {}} { set mand $regexdefaultlen } set extracted [GetString $offset $mand] if {[regexp -indices $val $extracted match indices]} { incr cursor [lindex $indices 1] set used [string length $match] set c 1 } else { set c 0 } } search { set limit $mand set extracted [GetString $offset $limit] if {[set offset2 [string first $val $extracted]] >= 0} { set cursor [expr {$offset + $offset2 + [string length $val]}] set used [string length $val] set c 1 } else { set c 0 } } default { # explicit "default" type, which is intended only to be used with # the "x" pattern set c [expr {[dict exists $lfound $level] ? ![dict get $lfound $level] : 1}] } default { # get the string and compare it switch $type bestring16 - lestring16 { set extracted [GetString $offset [ expr {2 * [string length $val]}]] switch $type bestring16 { binary scan $extracted Su* extracted } lestring16 { binary scan $extracted su* extracted } foreach ordinal $extracted[set extracted {}] { append extracted [format %c $ordinal] } } default { # If $val is 0, give [emit] something to work with . if {$val eq "\0"} { set extracted [GetString $offset $maxstring] } else { set extracted [GetString $offset [string length $val]] } } incr cursor [string length $extracted] set c [Smatch $val $comp $extracted $mod] } } ::fileutil::magic::rt::Debug { puts "String '$val' $comp '$extracted' - $c" if {$c} { puts "offset $offset - $extracted" } } if {$testinvert} { return [expr {!$c}] } else { return $c } } proc ::fileutil::magic::rt::Smatch {val op string mod} { upvar #1 class class level level typematch typematch useful useful if {$op eq {x}} { set useful($level) 0 return 1 } if {![string length $string] && $op in {eq == < <=}} { if {$op in {eq == < <=}} { # Nothing matches an empty $string. return 0 |
︙ | ︙ | |||
531 532 533 534 535 536 537 538 539 540 541 542 543 544 | } if {{T} in $mod} { set string [string trim $string[set string {}]] set val [string tolower $val[set val {}]] } set string [string range $string 0 [string length $val]-1] # The remaining code may assume that $string and $val have the same length # . set opnum [dict get {< -1 == 0 eq 0 != 0 ne 0 > 1} $op] | > > > > > > | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 | } if {{T} in $mod} { set string [string trim $string[set string {}]] set val [string tolower $val[set val {}]] } if {$class eq {binary} || {b} in $mod} { set typematch($level) 0 } else { set typematch($level) 1 } set string [string range $string 0 [string length $val]-1] # The remaining code may assume that $string and $val have the same length # . set opnum [dict get {< -1 == 0 eq 0 != 0 ne 0 > 1} $op] |
︙ | ︙ | |||
571 572 573 574 575 576 577 | } } else { set res [expr {[::string compare $string $val] == $opnum}] } if {$op in {!= ne}} { set res [expr {!$res}] } | > > | < < < < < < < < | | < | < | > | | < < < < | < < < < < < | | | < < | < < < < < < < < < < < < < < < | | | < < < | < < < < < < < < < | | < < < < < < < < < < < | < < < | < < < < < < < < > | | | | | | | | > > | | | | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > | > > > > | > > | > > > > > > > > < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < > | | > | > > > | > > | | | < < | | < | | > > > > > > > > > > > > > > < > > > > | | | | | | | > > > | < < < < < | < < < < | | < < | < < > > > | > | 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 | } } else { set res [expr {[::string compare $string $val] == $opnum}] } if {$op in {!= ne}} { set res [expr {!$res}] } # use the extracted value here, not val, because in the case of # inequalities the extra information has weight set useful($level) [string length $string] return $res } proc ::fileutil::magic::rt::T {offset mod} { upvar #1 cursors cursors level level offsets offsets tests tests \ virtual virtual if {{r} in $mod} { set offset [expr {$cursors($level) + $offset}] } set newvirtual [expr {$virtual($level) + $offset}] > set virtual($level) $newvirtual {*}$tests < } proc ::fileutil::magic::rt::U {file name offset} { upvar #1 level level named named offsets offsets set script [use $named $file $name] set offsets($level) $offset > ::try $script < } # ### ### ### ######### ######### ######### ## Internal. Retrieval of the data used in comparisons. # fetch and cache a numeric value from the file proc ::fileutil::magic::rt::Fetch {where what scan} { upvar #1 cache cache chan chan cursors cursors extracted extracted \ level level offsets offsets strbuf strbuf virtual virtual set where [expr {$virtual($level) + $where}] set offsets($level) $where # A negative offset means that an attempt to extract an indirect offset failed if {$where < 0} { return {} } # {to do} id3 length if {[info exists cache($where,$what,$scan)]} { lassign $cache($where,$what,$scan) extracted cursor } else { ::seek $chan $where set data [::read $chan $what] set cursor [expr {$where + [string length $data]}] set extracted [rtscan $data $scan] set cache($where,$what,$scan) [list $extracted $cursor] # Optimization: If we got 4 bytes, i.e. long we implicitly # know the short and byte data as well. Should put them into # the cache. -- Profile: How often does such an overlap truly # happen ? } set cursors($level) $cursor return $extracted } proc ::fileutil::magic::rt::GetString {offset len} { upvar #1 chan chan level level strbuf strbuf offsets offsets \ virtual virtual # We have the first 1k of the file cached set offsets($level) $offset set offset [expr {$virtual($level) + $offset}] set end [expr {$offset + $len - 1}] if {$end < [string length $strbuf]} { # in the string cache, copy the requested part. try { set string [::string range $strbuf $offset $end] } on error {tres topts} { lassign [dict get $topts -errorcode] TCL VALUE INDEX if {$TCL eq {TCL} && $VALUE eq {VALUE} && $INDEX eq {INDEX}} { set string {} } else { return -options $topts $tres } } } else { # an unusual one, move to the offset and read directly from # the file. ::seek $chan $offset try { # maybe offset is out of bounds set string [::read $chan $len] } on error {tres topts} { lassign [dict get $topts -errorcode] TCL VALUE INDEX if {$TCL eq {TCL} && $VALUE eq {VALUE} && $INDEX eq {INDEX}} { set string {} } else { return -options $topts $tres } } } return $string } proc ::fileutil::magic::rt::me4 data { binary scan $data a4 chars set data [binary format a4 [lindex $chars 1] [ lindex $chars 0] [lindex $chars 3] [lindex $chars 2]] } proc ::fileutil::magic::rt::rtscan {data scan} { if {$scan eq {me}} { set data [me4 $data] set scan I } set numeric {} binary scan $data $scan numeric return $numeric } # ### ### ### ######### ######### ######### ## Internal, debugging. if {!$::fileutil::magic::rt::debug} { # This procedure definition is optimized out of using code by the # core bcc. It knows that neither argument checks are required, # nor is anything done. So neither results, nor errors are # possible, a true no-operation. proc ::fileutil::magic::rt::Debug {args} {} } else { proc ::fileutil::magic::rt::Debug {script} { # Run the commands in the debug script. This usually generates # some output. The uplevel is required to ensure the proper # resolution of all variables found in the script. uplevel 1 $script return } } # ### ### ### ######### ######### ######### ## Initializ package proc ::fileutil::magic::rt::Init {} { variable typemap global tcl_platform # map magic typenames to field characteristics: size (#byte), # Types without explicit endianess assume/use 'native' byteorder. # We also put in special forms for the compiler, so that it can use short # names for the native-endian types as well. # {to do} {Is ldate done correctly in the procedure? What is its byte # order anyway? Native?} foreach {type sig} { bedate {4 S} bedouble {8 Q} befloat {4 R} beid3 {4 n} beldate {4 I} belong {4 I} beqdate {8 W} beqldate {8 W} beqwdate {8 W} beqldate {8 W} bequad {8 W} beshort {2 S} bestring16 {2 S} byte {1 c} date {4 n} double {8 d} float {4 f} ldate {4 n} ledate {4 n} ledouble {8 q} leid3 {4 nu} lefloat {4 f} leldate {4 i} lelong {4 i} leqdate {8 w} leqldate {8 w} lequad {8 w} leqwdate {8 w} leshort {2 s} lestring16 {2 s} long {4 n} medate {4 me} meldate {4 me} melong {4 me} qdate {8 m} qdate {8 n} qldata {8 m} quad {8 m} qwdate {8 m} short {2 t} } { set typemap($type) $sig lassign $sig size scan set typemap(u$type) [list $size ${scan}u] } # generate short form names foreach {n v} [array get typemap] { foreach {len scan} $v break set typemap($scan) [list $len $scan] } # Add the special Q and Y short forms using the proper native endianess. if {$tcl_platform(byteOrder) eq {littleEndian}} { array set typemap {Q {4 i} Y {2 s} quad {8 w}} } else { array set typemap {Q {4 I} Y {2 S} quad {8 W}} } } ::fileutil::magic::rt::Init # ### ### ### ######### ######### ######### ## Ready for use. package provide fileutil::magic::rt 3.0 # EOF |
Changes to modules/fumagic/tmc.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # (-) Compilation of one or more files in magic(5) syntax into a # list of recognizers performing all the checks and mappings # encoded in them. # # Command syntax # -------------- # | | | | | | 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 | # (-) Compilation of one or more files in magic(5) syntax into a # list of recognizers performing all the checks and mappings # encoded in them. # # Command syntax # -------------- # # Ad 1) tmc magic-file ?magic-file...? # # Compile all magic files list of recognizers, generate a script which # assigns the recognizers to $tests and $named and # write the script to stdout. # # Ad 2) tmc -merge tclfile magic-file ?magic-file...? # # Same as (1), but does not write to stdout. Instead the part of # the 'tclfile' delineated by marker lines containing "BEGIN # GENERATED CODE" and "END GENERATED CODE" is replaced with the # generated code. package require Tcl 8.5 set auto_path [linsert $auto_path 0 [file dirname [file normalize [info script]]]] ; # This directory set auto_path [linsert $auto_path 0 [file dirname [lindex $auto_path end]]] ; # and the one above #puts *\t[join $auto_path \n*\t] package require fileutil::magic::cfront # ### ### ### ######### ######### ######### ## Internal data and status namespace eval ::tmc { |
︙ | ︙ | |||
73 74 75 76 77 78 79 | ## proc ::tmc::processCmdline {} { global argv variable output variable magic | < < | < < < < | 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 | ## proc ::tmc::processCmdline {} { global argv variable output variable magic set output "" set magic {} # Process the options, perform basic validation. while {[llength $argv]} { set opt [lindex $argv 0] if {![string match "-*" $opt]} break if {$opt eq "-merge"} { if {[llength $argv] < 2} Usage set output [lindex $argv 1] set argv [lrange $argv 2 end] } else { Usage } } # Additional validation, and extraction of the non-option # arguments. if {[llength $argv] < 1} Usage set magic [lrange $argv 1 end] # Final validation across the whole configuration. foreach m $magic { CheckInput $m {Magic file} } if {$output ne ""} { CheckTheMerge } return |
︙ | ︙ | |||
128 129 130 131 132 133 134 | # Both write their messages to stderr and then # exit the application with status 1. ## proc ::tmc::Usage {} { global argv0 puts stderr "$argv0 wrong#args, expected:\ | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | # Both write their messages to stderr and then # exit the application with status 1. ## proc ::tmc::Usage {} { global argv0 puts stderr "$argv0 wrong#args, expected:\ ?-merge iofile? magic magic..." exit 1 } proc ::tmc::ArgError {text} { global argv0 puts stderr "$argv0: $text" exit 1 |
︙ | ︙ | |||
181 182 183 184 185 186 187 | ## Helper commands. File reading and writing. proc ::tmc::Get {f} { return [read [set in [open $f r]]][close $in] } proc ::tmc::Write {f data} { | > > > > | > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | ## Helper commands. File reading and writing. proc ::tmc::Get {f} { return [read [set in [open $f r]]][close $in] } proc ::tmc::Write {f data} { while 1 { set tmp $f.tmc_[incr i] if {![file exists $tmp]} break } puts -nonewline [set out [open $tmp w]] $data close $out file rename -force $tmp $f return } # ### ### ### ######### ######### ######### ## Configuation phase, validate command line. ::tmc::processCmdline |
︙ | ︙ | |||
223 224 225 226 227 228 229 | } # ### ### ### ######### ######### ######### ## Invoking the functionality. if {[catch { # Read and process all input files. | < | < | | 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 | } # ### ### ### ######### ######### ######### ## Invoking the functionality. if {[catch { # Read and process all input files. # Write the result either to stdout, or merge # into the specified output file. set tcl [eval [linsert $tmc::magic 0 \ fileutil::magic::cfront::generate compressed 0 --]] if {$tmc::output eq {}} { puts stdout $tcl } else { ::tmc::Merge $tmc::output \n${tcl}\n } } msg]} { puts $::errorInfo ::tmc::ArgError $msg } # ### ### ### ######### ######### ######### exit |
Changes to modules/htmlparse/htmlparse.man.
︙ | ︙ | |||
134 135 136 137 138 139 140 | error if it sees incomplete HTML and has no place to store it to. This makes sense for the normal mode. Only incomplete tags are detected, not missing tags. Optional, defaults to 'no variable'. [list_end] [list_begin definitions] | | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | error if it sees incomplete HTML and has no place to store it to. This makes sense for the normal mode. Only incomplete tags are detected, not missing tags. Optional, defaults to 'no variable'. [list_end] [list_begin definitions] [def [emph "Interface to the command prefix"]] In normal mode the parser will invoke the command prefix with four arguments appended. See [cmd ::htmlparse::debugCallback] for a description. [para] |
︙ | ︙ |
Changes to modules/httpd/build/build.tcl.
1 2 3 | set srcdir [file dirname [file normalize [file join [pwd] [info script]]]] set moddir [file dirname $srcdir] | > > > > | > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | set srcdir [file dirname [file normalize [file join [pwd] [info script]]]] set moddir [file dirname $srcdir] if {[catch {package require clay 0.3}]} { source [file join $moddir .. clay build doctool.tcl] } ::clay::doctool create AutoDoc set version 4.3 set tclversion 8.6 set module [file tail $moddir] set filename $module set fout [open [file join $moddir ${filename}.tcl] w] dict set map %module% $module dict set map %version% $version dict set map %tclversion% $tclversion dict set map %filename% $filename dict set map { } {} ;# strip indentation dict set map "\t" { } ;# reduce indentation (see cleanup) puts $fout [string map $map {### # Amalgamated package for %module% # Do not edit directly, tweak the source in src/ and rerun # build.tcl |
︙ | ︙ | |||
35 36 37 38 39 40 41 | file.tcl proxy.tcl cgi.tcl scgi.tcl websocket.tcl } { lappend loaded $file | < > > | < > > | < > > > > > > > | 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 | file.tcl proxy.tcl cgi.tcl scgi.tcl websocket.tcl } { lappend loaded $file puts $fout "###\n# START: [file tail $file]\n###" set content [::clay::cat [file join $srcdir $file]] AutoDoc scan_text $content puts $fout $content puts $fout "###\n# END: [file tail $file]\n###" } # These files can be loaded in any order foreach file [glob [file join $srcdir *.tcl]] { if {[file tail $file] in $loaded} continue lappend loaded $file set fin [open [file join $srcdir $file] r] puts $fout "###\n# START: [file tail $file]\n###" set content [::clay::cat [file join $srcdir $file]] AutoDoc scan_text $content puts $fout $content puts $fout "###\n# END: [file tail $file]\n###" } # Provide some cleanup and our final package provide puts $fout [string map $map { namespace eval ::%module% { namespace export * } }] close $fout ### # Build our pkgIndex.tcl file ### set fout [open [file join $moddir pkgIndex.tcl] w] puts $fout [string map $map { if {![package vsatisfies [package provide Tcl] %tclversion%]} {return} package ifneeded %module% %version% [list source [file join $dir %module%.tcl]] }] close $fout set manout [open [file join $moddir $filename.man] w] puts $manout [AutoDoc manpage \ header [string map $map [::clay::cat [file join $srcdir manual.txt]]] \ footer [string map $map [::clay::cat [file join $srcdir footer.txt]]] \ ] close $manout |
Changes to modules/httpd/build/cgi.tcl.
|
| | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ::clay::define ::httpd::content.cgi { superclass ::httpd::content.proxy method FileName {} { set uri [string trimleft [my request get REQUEST_URI] /] set path [my clay get path] set prefix [my clay get prefix] set fname [string range $uri [string length $prefix] end] if {[file exists [file join $path $fname]]} { return [file join $path $fname] } if {[file exists [file join $path $fname.fossil]]} { return [file join $path $fname.fossil] |
︙ | ︙ | |||
24 25 26 27 28 29 30 | method proxy_channel {} { ### # When delivering static content, allow web caches to save ### set local_file [my FileName] if {$local_file eq {} || ![file exist $local_file]} { | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | method proxy_channel {} { ### # When delivering static content, allow web caches to save ### set local_file [my FileName] if {$local_file eq {} || ![file exist $local_file]} { my log httpNotFound [my request get REQUEST_URI] my error 404 {Not Found} tailcall my DoOutput } if {[file isdirectory $local_file]} { ### # Produce an index page... or error ### |
︙ | ︙ | |||
48 49 50 51 52 53 54 | } foreach item $verbatim { set ::env($item) {} } foreach item [array names ::env HTTP_*] { set ::env($item) {} } | | | < | < < < < < < < < | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | } foreach item $verbatim { set ::env($item) {} } foreach item [array names ::env HTTP_*] { set ::env($item) {} } set ::env(SCRIPT_NAME) [my request get REQUEST_PATH] set ::env(SERVER_PROTOCOL) HTTP/1.0 set ::env(HOME) $::env(DOCUMENT_ROOT) foreach {f v} [my request dump] { set ::env($f) $v } set arglist $::env(QUERY_STRING) set pwd [pwd] cd [file dirname $local_file] set script_file $local_file if {[file extension $local_file] in {.fossil .fos}} { if {![file exists $local_file.cgi]} { set fout [open $local_file.cgi w] chan puts $fout "#!/usr/bin/fossil" chan puts $fout "repository: $local_file" close $fout |
︙ | ︙ | |||
88 89 90 91 92 93 94 | cd $pwd return $pipe } method ProxyRequest {chana chanb} { chan event $chanb writable {} my log ProxyRequest {} | | | < > < | 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 | cd $pwd return $pipe } method ProxyRequest {chana chanb} { chan event $chanb writable {} my log ProxyRequest {} set length [my request get CONTENT_LENGTH] if {$length} { chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 ### # Send any POST/PUT/etc content ### my ChannelCopy $chana $chanb -size $length } else { chan flush $chanb } chan event $chanb readable [info coroutine] yield } method ProxyReply {chana chanb args} { my log ProxyReply [list args $args] chan event $chana readable {} set replyhead [my HttpHeaders $chana] |
︙ | ︙ | |||
124 125 126 127 128 129 130 | # a standard service reply line from a web server, but # otherwise spit out the rest of the headers verbatim ### set replybuffer "HTTP/1.0 [dict get $replydat Status]\n" append replybuffer $replyhead chan configure $chanb -translation {auto crlf} -blocking 0 -buffering full -buffersize 4096 chan puts $chanb $replybuffer | < < | | | | | < < | < | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | # a standard service reply line from a web server, but # otherwise spit out the rest of the headers verbatim ### set replybuffer "HTTP/1.0 [dict get $replydat Status]\n" append replybuffer $replyhead chan configure $chanb -translation {auto crlf} -blocking 0 -buffering full -buffersize 4096 chan puts $chanb $replybuffer ### # Output the body. With no -size flag, channel will copy until EOF ### chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 my ChannelCopy $chana $chanb -chunk 4096 } ### # For most CGI applications a directory list is vorboten ### method DirectoryListing {local_file} { my error 403 {Not Allowed} tailcall my DoOutput } } |
Deleted modules/httpd/build/content.man.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to modules/httpd/build/core.tcl.
︙ | ︙ | |||
10 11 12 13 14 15 16 | # support the SCGI module ### package require uri package require dns package require cron package require coroutine | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | # support the SCGI module ### package require uri package require dns package require cron package require coroutine package require clay 0.3 package require mime package require fileutil package require websocket package require Markdown package require uuid package require fileutil::magic::filetype namespace eval httpd::content {} namespace eval ::url {} namespace eval ::httpd {} namespace eval ::scgi {} clay::define ::httpd::mime { method ChannelCopy {in out args} { set chunk 4096 set size -1 foreach {f v} $args { set [string trim $f -] $v } dict set info coroutine [info coroutine] if {$size>0 && $chunk>$size} { set chunk $size } set bytes 0 set sofar 0 set method [self method] while 1 { set command {} set error {} if {$size>=0} { incr sofar $bytes set remaining [expr {$size-$sofar}] if {$remaining <= 0} { break } elseif {$chunk > $remaining} { set chunk $remaining } } lassign [yieldto chan copy $in $out -size $chunk \ -command [list [info coroutine] $method]] \ command bytes error if {$command ne $method} { error "Subroutine $method interrupted" } if {[string length $error]} { error $error } if {[chan eof $in]} { break } } } method html_header {{title {}} args} { set result {} append result "<HTML><HEAD>" if {$title ne {}} { append result "<TITLE>$title</TITLE>" |
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 | method HttpHeaders_Default {} { return {Status {200 OK} Content-Size 0 Content-Type {text/html; charset=UTF-8} Cache-Control {no-cache} Connection close} } ### | > > > > > > > > > > < > > > | 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 | method HttpHeaders_Default {} { return {Status {200 OK} Content-Size 0 Content-Type {text/html; charset=UTF-8} Cache-Control {no-cache} Connection close} } method HttpServerHeaders {} { return { CONTENT_LENGTH CONTENT_TYPE QUERY_STRING REMOTE_USER AUTH_TYPE REQUEST_METHOD REMOTE_ADDR REMOTE_HOST REQUEST_URI REQUEST_PATH REQUEST_VERSION DOCUMENT_ROOT QUERY_STRING REQUEST_RAW GATEWAY_INTERFACE SERVER_PORT SERVER_HTTPS_PORT SERVER_NAME SERVER_SOFTWARE SERVER_PROTOCOL } } ### # 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. ### method MimeParse mimetext { set data(mimeorder) {} foreach line [split $mimetext \n] { # This regexp picks up # key: value # MIME headers. MIME headers may be continue with a line |
︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 202 203 204 205 206 | } } dict set result $ckey $data(mime,$key) } return $result } method Url_Decode data { regsub -all {\+} $data " " data regsub -all {([][$\\])} $data {\\\1} data regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data {[format %c 0x\1]} data return [subst $data] } | > | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | } } dict set result $ckey $data(mime,$key) } return $result } # De-httpizes a string. method Url_Decode data { regsub -all {\+} $data " " data regsub -all {([][$\\])} $data {\\\1} data regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data {[format %c 0x\1]} data return [subst $data] } |
︙ | ︙ |
Changes to modules/httpd/build/dispatch.tcl.
|
| | | | | | | | | < < < < < | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | ::clay::define ::httpd::content.redirect { method reset {} { ### # Inject the location into the HTTP headers ### my variable reply_body set reply_body {} my reply replace [my HttpHeaders_Default] my reply set Server [my <server> clay get server/ string] set msg [my clay get LOCATION] my reply set Location [my clay get LOCATION] set code [my clay get REDIRECT_CODE] if {$code eq {}} { set code 301 } my reply set Status [list $code [my http_code_string $code]] } method content {} { set template [my <server> template redirect] set msg [my clay get LOCATION] set HTTP_STATUS [my reply get Status] my puts [subst $msg] } } ::clay::define ::httpd::content.cache { method Dispatch {} { my variable chan try { my wait writable $chan chan configure $chan -translation {binary binary} chan puts -nonewline $chan [my clay get cache/ data] } on error {err info} { my <server> debug [dict get $info -errorinfo] } finally { my TransferComplete $chan } } } ::clay::define ::httpd::content.template { method content {} { if {[my request get HTTP_STATUS] ne {}} { my reply set Status [my request get HTTP_STATUS] } my puts [subst [my <server> template [my clay get template]]] } } |
Changes to modules/httpd/build/file.tcl.
1 2 3 4 5 | ### # Class to deliver Static content # When utilized, this class is fed a local filename # by the dispatcher ### | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ### # Class to deliver Static content # When utilized, this class is fed a local filename # by the dispatcher ### ::clay::define ::httpd::content.file { method FileName {} { set uri [string trimleft [my request get REQUEST_URI] /] set path [my clay get path] set prefix [my clay get prefix] set fname [string range $uri [string length $prefix] end] if {$fname in "{} index.html index.md index"} { return $path } if {[file exists [file join $path $fname]]} { return [file join $path $fname] } if {[file exists [file join $path $fname.md]]} { return [file join $path $fname.md] } if {[file exists [file join $path $fname.html]]} { return [file join $path $fname.html] } if {[file exists [file join $path $fname.tml]]} { return [file join $path $fname.tml] } return {} } method DirectoryListing {local_file} { set uri [string trimleft [my request get REQUEST_URI] /] set path [my clay get path] set prefix [my clay get prefix] set fname [string range $uri [string length $prefix] end] my puts [my html_header "Listing of /$fname/"] my puts "Listing contents of /$fname/" my puts "<TABLE>" if {$prefix ni {/ {}}} { set updir [file dirname $prefix] if {$updir ne {}} { |
︙ | ︙ | |||
53 54 55 56 57 58 59 | my puts [my html_footer] } method content {} { my variable reply_file set local_file [my FileName] if {$local_file eq {} || ![file exist $local_file]} { | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | my puts [my html_footer] } method content {} { my variable reply_file set local_file [my FileName] if {$local_file eq {} || ![file exist $local_file]} { my log httpNotFound [my request get REQUEST_URI] my error 404 {File Not Found} tailcall my DoOutput } if {[file isdirectory $local_file] || [file tail $local_file] in {index index.html index.tml index.md}} { ### # Produce an index page ### |
︙ | ︙ | |||
88 89 90 91 92 93 94 | my reply set Content-Type {text/html; charset=UTF-8} set mdtxt [::fileutil::cat $local_file] my puts [::Markdown::convert $mdtxt] } .tml { my reply set Content-Type {text/html; charset=UTF-8} set tmltxt [::fileutil::cat $local_file] | | | < < < < < < < | 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 | my reply set Content-Type {text/html; charset=UTF-8} set mdtxt [::fileutil::cat $local_file] my puts [::Markdown::convert $mdtxt] } .tml { my reply set Content-Type {text/html; charset=UTF-8} set tmltxt [::fileutil::cat $local_file] set headers [my request dump] dict with headers {} my puts [subst $tmltxt] } default { ### # Assume we are returning a binary file ### my reply set Content-Type [::fileutil::magic::filetype $local_file] set reply_file $local_file } } } method Dispatch {} { my variable reply_body reply_file reply_chan chan try { my reset # Invoke the URL implementation. my content } on error {err errdat} { my error 500 $err [dict get $errdat -errorinfo] tailcall my DoOutput } |
︙ | ︙ | |||
136 137 138 139 140 141 142 | ### set size [file size $reply_file] my reply set Content-Length $size append result [my reply output] \n chan puts -nonewline $chan $result set reply_chan [open $reply_file r] my log SendReply [list length $size] | < | < < < < < < < < < > | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | ### set size [file size $reply_file] my reply set Content-Length $size append result [my reply output] \n chan puts -nonewline $chan $result set reply_chan [open $reply_file r] my log SendReply [list length $size] ### # Output the file contents. With no -size flag, channel will copy until EOF ### chan configure $reply_chan -translation {binary binary} -buffersize 4096 -buffering full -blocking 0 my ChannelCopy $reply_chan $chan -chunk 4096 } finally { my TransferComplete $reply_chan $chan } } } |
Added modules/httpd/build/footer.txt.
> > > > > | 1 2 3 4 5 | [section AUTHORS] Sean Woods [vset CATEGORY network] [include ../doctools2base/include/feedback.inc] |
Added modules/httpd/build/manual.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | [vset VERSION %version%] [comment {-*- tcl -*- doctools manpage}] [manpage_begin %module% n [vset VERSION]] [keywords WWW] [copyright {2018 Sean Woods <[email protected]>}] [moddesc {Tcl Web Server}] [titledesc {A TclOO and coroutine based web server}] [category Networking] [keywords TclOO] [keywords http] [keywords httpd] [keywords httpserver] [keywords services] [require Tcl 8.6] [require httpd [opt [vset VERSION]]] [require uuid] [require clay] [require coroutine] [require fileutil] [require fileutil::magic::filetype] [require websocket] [require mime] [require cron] [require uri] [require Markdown] [description] [para] This module implements a web server, suitable for embedding in an application. The server is object oriented, and contains all of the fundamentals needed for a full service website. [para] [section {Minimal Example}] Starting a web service requires starting a class of type [cmd httpd::server], and providing that server with one or more URIs to service, and [cmd httpd::reply] derived classes to generate them. [example { oo::class create ::reply.hello { method content {} { my puts "<HTML><HEAD><TITLE>IRM Dispatch Server</TITLE></HEAD><BODY>" my puts "<h1>Hello World!</h1>" my puts </BODY></HTML> } } ::httpd::server create HTTPD port 8015 myaddr 127.0.0.1 doc_root ~/htdocs HTTPD plugin dispatch httpd::server::dispatch HTTPD uri add * /hello [list mixin reply.hello] }] The bare module does have facilities to hose a files from a file system. Files that end in a .tml will be substituted in the style of Tclhttpd: [example { <!-- hello.tml --> [my html_header {Hello World!}] Your Server is running. <p> The time is now [clock format [clock seconds]] [my html_footer] }] A complete example of an httpd server is in the /examples directory of Tcllib. It also show how to dispatch URIs to other processes via SCGI and HTTP proxies. [example { cd ~/tcl/sandbox/tcllib tclsh examples/httpd.tcl }] |
Changes to modules/httpd/build/plugin.tcl.
1 2 3 | ### # httpd plugin template ### | | | | | | | | | > > > > | | | > | | | | | | | < | | < < < < < < < | | < < < > | | | < < < < < < < < < < < < < | > > > > > > | > > > > > > > > > > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | ### # httpd plugin template ### ::clay::define ::httpd::plugin { ### # Any options will be saved to the local config file # to allow threads to pull up a snapshot of the object' configuration ### ### # Define a code snippet to run on plugin load ### clay set plugin/ load {} ### # Define a code snippet to run within the object's Headers_Process method ### clay set plugin/ headers {} ### # Define a code snippet to run within the object's dispatch method ### clay set plugin/ dispatch {} ### # Define a code snippet to run within the object's writes a local config file ### clay set plugin/ local_config {} ### # When after all the plugins are loaded # allow specially configured ones to light off a thread ### clay set plugin/ thread {} } ### # A rudimentary plugin that dispatches URLs from a dict # data structure ### ::clay::define ::httpd::plugin.dict_dispatch { clay set plugin/ dispatch { set reply [my Dispatch_Dict $data] if {[dict size $reply]} { return $reply } } ### # Implementation of the dispatcher ### method Dispatch_Dict {data} { my variable url_patterns set vhost [lindex [split [dict get $data http HTTP_HOST] :] 0] set uri [dict get $data http REQUEST_PATH] foreach {host hostpat} $url_patterns { if {![string match $host $vhost]} continue foreach {pattern info} $hostpat { if {![string match $pattern $uri]} continue set buffer $data foreach {f v} $info { dict set buffer $f $v } return $buffer } } return {} } ### # Ensemble uri::add {vhosts patterns info} { my variable url_patterns foreach vhost $vhosts { foreach pattern $patterns { set data $info if {![dict exists $data prefix]} { dict set data prefix [my PrefixNormalize $pattern] } dict set url_patterns $vhost [string trimleft $pattern /] $data } } } Ensemble uri::direct {vhosts patterns info body} { my variable url_patterns url_stream set cbody {} if {[dict exists $info superclass]} { append cbody \n "superclass {*}[dict get $info superclass]" dict unset info superclass } append cbody \n [list method content {} $body] set class [namespace current]::${vhosts}/${patterns} set class [string map {* %} $class] ::clay::define $class $cbody dict set info mixin content $class my uri add $vhosts $patterns $info } } ::clay::define ::httpd::reply.memchan { superclass ::httpd::reply method output {} { my variable reply_body return $reply_body } method DoOutput {} {} method close {} { # Neuter the channel closing mechanism we need the channel to stay alive # until the reader sucks out the info } } ::clay::define ::httpd::plugin.local_memchan { clay set plugin/ load { package require tcl::chan::events package require tcl::chan::memchan } method local_memchan {command args} { my variable sock_to_coro switch $command { |
︙ | ︙ | |||
157 158 159 160 161 162 163 | chan configure $sock \ -blocking 0 \ -translation {auto crlf} \ -buffering line set ip 127.0.0.1 dict set query UUID $uuid | > | | | | | | | | | | | | | | | | < < < | | | | 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 | chan configure $sock \ -blocking 0 \ -translation {auto crlf} \ -buffering line set ip 127.0.0.1 dict set query UUID $uuid dict set query http UUID $uuid dict set query http HTTP_HOST localhost dict set query http REMOTE_ADDR 127.0.0.1 dict set query http REMOTE_HOST localhost dict set query http LOCALHOST 1 my counter url_hit dict set query http REQUEST_METHOD [lindex $args 0] set uriinfo [::uri::split [lindex $args 1]] dict set query http REQUEST_URI [lindex $args 1] dict set query http REQUEST_PATH [dict get $uriinfo path] dict set query http REQUEST_VERSION [lindex [split [lindex $args end] /] end] dict set query http DOCUMENT_ROOT [my clay get server/ doc_root] dict set query http QUERY_STRING [dict get $uriinfo query] dict set query http REQUEST_RAW $args dict set query http SERVER_PORT [my port_listening] my Headers_Process query set reply [my dispatch $query] if {[llength $reply]==0} { my log BadLocation $uuid $query my log BadLocation $uuid $query dict set query http HTTP_STATUS 404 dict set query template notfound dict set query mixin reply ::httpd::content.template } set class ::httpd::reply.memchan set pageobj [$class create ::httpd::object::$uuid [self]] if {[dict exists $reply mixin]} { set mixinmap [dict get $reply mixin] } else { set mixinmap {} } foreach item [dict keys $reply MIXIN_*] { set slot [string range $reply 6 end] dict set mixinmap [string tolower $slot] [dict get $reply $item] } $pageobj clay mixinmap {*}$mixinmap if {[dict exists $reply delegate]} { $pageobj clay delegate {*}[dict get $reply delegate] } $pageobj dispatch $sock $reply set output [$pageobj output] catch {$pageobj destroy} return $output } } |
Changes to modules/httpd/build/proxy.tcl.
|
| | | 1 2 3 4 5 6 7 8 | ::clay::define ::httpd::content.exec { variable exename [list tcl [info nameofexecutable] .tcl [info nameofexecutable]] method CgiExec {execname script arglist} { if { $::tcl_platform(platform) eq "windows"} { if {[file extension $script] eq ".exe"} { return [open "|[list $script] $arglist" r+] } else { |
︙ | ︙ | |||
56 57 58 59 60 61 62 | return $result } } if {[dict exists exename $which]} { return [dict get $exename $which] } if {$which eq "tcl"} { | | | | | | | | | > | | | < > < < < < | < < | | | | | < < | | | < < < < < | | < < < < < < < < < > | | > > | | > | 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 | return $result } } if {[dict exists exename $which]} { return [dict get $exename $which] } if {$which eq "tcl"} { if {[my clay get tcl_exe] ne {}} { dict set exename $which [my clay get tcl_exe] } else { dict set exename $which [info nameofexecutable] } } else { if {[my clay get ${which}_exe] ne {}} { dict set exename $which [my clay get ${which}_exe] } elseif {"$::tcl_platform(platform)" == "windows"} { dict set exename $which $which.exe } else { dict set exename $which $which } } set result [dict get $exename $which] if {$ext ne {}} { dict set exename $ext $result } return $result } } ### # Return data from an proxy process ### ::clay::define ::httpd::content.proxy { superclass ::httpd::content.exec method proxy_channel {} { ### # This method returns a channel to the # proxied socket/stdout/etc ### error unimplemented } method proxy_path {} { set uri [string trimleft [my request get REQUEST_URI] /] set prefix [my clay get prefix] return /[string range $uri [string length $prefix] end] } method ProxyRequest {chana chanb} { chan event $chanb writable {} my log ProxyRequest {} chan puts $chanb "[my request get REQUEST_METHOD] [my proxy_path]" set mimetxt [my clay get mimetxt] chan puts $chanb [my clay get mimetxt] set length [my request get CONTENT_LENGTH] if {$length} { chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 ### # Send any POST/PUT/etc content ### my ChannelCopy $chana $chanb -size $length } else { chan flush $chanb } chan event $chanb readable [info coroutine] yield } method ProxyReply {chana chanb args} { my log ProxyReply [list args $args] chan event $chana readable {} set readCount [::coroutine::util::gets_safety $chana 4096 reply_status] set replyhead [my HttpHeaders $chana] set replydat [my MimeParse $replyhead] ### # Read the first incoming line as the HTTP reply status # Return the rest of the headers verbatim ### set replybuffer "$reply_status\n" append replybuffer $replyhead chan configure $chanb -translation {auto crlf} -blocking 0 -buffering full -buffersize 4096 chan puts $chanb $replybuffer ### # Output the body. With no -size flag, channel will copy until EOF ### chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 my ChannelCopy $chana $chanb -chunk 4096 } method Dispatch {} { my variable sock chan if {[catch {my proxy_channel} sock errdat]} { my error 504 {Service Temporarily Unavailable} [dict get $errdat -errorinfo] tailcall my DoOutput } if {$sock eq {}} { my error 404 {Not Found} tailcall my DoOutput } my log HttpAccess {} chan event $sock writable [info coroutine] yield try { my ProxyRequest $chan $sock my ProxyReply $sock $chan } finally { my TransferComplete $chan $sock } } } |
Deleted modules/httpd/build/reply.man.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to modules/httpd/build/reply.tcl.
1 | ### | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > | | | > > > > > > | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | | > > > | > | | | > | | < | > > > | > | < > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | ### # 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] # # 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] # } # } # # }] ### ::clay::define ::httpd::reply { superclass ::httpd::mime Variable transfer_complete 0 Dict reply {} Dict request { CONTENT_LENGTH 0 COOKIE {} HTTP_HOST {} REFERER {} REQUEST_URI {} REMOTE_ADDR {} REMOTE_HOST {} USER_AGENT {} SESSION {} } constructor {ServerObj args} { my variable chan dispatched_time uuid set uuid [namespace tail [self]] set dispatched_time [clock milliseconds] my clay delegate <server> $ServerObj foreach {field value} [::clay::args_to_options {*}$args] { my clay set config $field: $value } } ### # clean up on exit ### destructor { my close } ### # Close channels opened by this object ### method close {} { my variable chan if {[info exists chan] && $chan ne {}} { catch {chan event $chan readable {}} catch {chan event $chan writable {}} catch {chan flush $chan} catch {chan close $chan} set chan {} } } ### # Record a dispatch event ### method Log_Dispatched {} { my log Dispatched [dict create \ REMOTE_ADDR [my request get REMOTE_ADDR] \ REMOTE_HOST [my request get REMOTE_HOST] \ COOKIE [my request get HTTP_COOKIE] \ REFERER [my request get HTTP_REFERER] \ USER_AGENT [my request get HTTP_USER_AGENT] \ REQUEST_URI [my request get REQUEST_URI] \ 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 if {[dict exists $datastate mixin]} { set mixinmap [dict get $datastate mixin] } else { set mixinmap {} } foreach item [dict keys $datastate MIXIN_*] { set slot [string range $item 6 end] dict set mixinmap [string tolower $slot] [dict get $datastate $item] } my clay mixinmap {*}$mixinmap if {[dict exists $datastate delegate]} { my clay delegate {*}[dict get $datastate delegate] } my reset set request [my clay get dict/ request] foreach {f v} $datastate { if {[string index $f end] eq "/"} { my clay merge $f $v } else { my clay set $f $v } if {$f eq "http"} { foreach {ff vf} $v { dict set request $ff $vf } } } my Session_Load my Log_Dispatched my Dispatch } on error {err errdat} { my error 500 $err [dict get $errdat -errorinfo] my DoOutput } } method Dispatch {} { # Invoke the URL implementation. my content my DoOutput } method html_css {} { set result "<link rel=\"stylesheet\" href=\"/style.css\">" append result \n {<style media="screen" type="text/css"> body { background: url(images/etoyoc-circuit-tile.gif) repeat; |
︙ | ︙ | |||
101 102 103 104 105 106 107 | } method html_footer {args} { set result {</div><div id="footer">} append result {</div></BODY></HTML>} } | < < < < < < < < < < < < < | | < | > > > | | | | 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 | } method html_footer {args} { set result {</div><div id="footer">} append result {</div></BODY></HTML>} } method error {code {msg {}} {errorInfo {}}} { my clay set HTTP_ERROR $code my reset set qheaders [my clay dump] set HTTP_STATUS "$code [my http_code_string $code]" dict with qheaders {} my reply replace {} my reply set Status $HTTP_STATUS my reply set Content-Type {text/html; charset=UTF-8} switch $code { 301 - 302 - 303 - 307 - 308 { my reply set Location $msg set template [my <server> template redirect] } 404 { set template [my <server> template notfound] } default { set template [my <server> template internal_error] } } my puts [subst $template] } ### # 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" ### method content {} { my puts [my html_header {Hello World!}] my puts "<H1>HELLO WORLD!</H1>" my puts [my html_footer] } ### # Formulate a standard HTTP status header from he string provided. ### method EncodeStatus {status} { return "HTTP/1.0 $status" } method log {type {info {}}} { my variable dispatched_time uuid my <server> log $type $uuid $info } method CoroName {} { if {[info coroutine] eq {}} { return ::httpd::object::[my clay get UUID] } } ### # Generates the the HTTP reply, streams that reply back across [arg chan], # and destroys the object. ### method DoOutput {} { my variable reply_body chan if {$chan eq {}} return catch { my wait writable $chan chan configure $chan -translation {binary binary} |
︙ | ︙ | |||
195 196 197 198 199 200 201 202 203 204 205 206 207 | } chan puts -nonewline $chan $result my log HttpAccess {} } my destroy } method FormData {} { my variable chan formdata # Run this only once if {[info exists formdata]} { return $formdata } | > > > > > > > > > < < < | < | | | 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 | } chan puts -nonewline $chan $result my log HttpAccess {} } my destroy } ### # 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. ### method FormData {} { my variable chan formdata # Run this only once if {[info exists formdata]} { return $formdata } set length [my request get CONTENT_LENGTH] set formdata {} if {[my request get REQUEST_METHOD] in {"POST" "PUSH"}} { set rawtype [my request get CONTENT_TYPE] if {[string toupper [string range $rawtype 0 8]] ne "MULTIPART"} { set type $rawtype } else { set type multipart } switch $type { multipart { ### # Ok, Multipart MIME is troublesome, farm out the parsing to a dedicated tool ### set body [my clay get mimetxt] append body \n [my PostData $length] set token [::mime::initialize -string $body] foreach item [::mime::getheader $token -names] { dict set formdata $item [::mime::getheader $token $item] } foreach item {content encoding params parts size} { dict set formdata MIME_[string toupper $item] [::mime::getproperty $token $item] |
︙ | ︙ | |||
243 244 245 246 247 248 249 | foreach {name value} [split $pair "="] { lappend formdata [my Url_Decode $name] [my Url_Decode $value] } } } } } else { | | > > | > > > > > > > > > > > > > > > > > > > > > > > > < | | > | > > > > | | | | | | | | | | | | | | | | | < | | | | | | | | | | | > > | > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | > > | > > | | > | < < > > | | | | > | | 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 | foreach {name value} [split $pair "="] { lappend formdata [my Url_Decode $name] [my Url_Decode $value] } } } } } else { foreach pair [split [my clay get QUERY_STRING] "&"] { foreach {name value} [split $pair "="] { lappend formdata [my Url_Decode $name] [my Url_Decode $value] } } } return $formdata } # Stream [arg length] bytes from the [arg chan] socket, but only of the request is a # POST or PUSH. Returns an empty string otherwise. method PostData {length} { my variable postdata # Run this only once if {[info exists postdata]} { return $postdata } set postdata {} if {[my request get REQUEST_METHOD] in {"POST" "PUSH"}} { my variable chan chan configure $chan -translation binary -blocking 0 -buffering full -buffersize 4096 set postdata [::coroutine::util::read $chan $length] } return $postdata } # Manage session data method Session_Load {} {} # 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 # }] method TransferComplete args { my variable chan transfer_complete set transfer_complete 1 my log TransferComplete set chan {} foreach c $args { catch {chan event $c readable {}} catch {chan event $c writable {}} catch {chan flush $c} catch {chan close $c} } my destroy } # Appends the value of [arg string] to the end of [arg reply_body], as well as a trailing newline # character. method puts line { my variable reply_body append reply_body $line \n } method RequestFind {field} { my variable request if {[dict exists $request $field]} { return $field } foreach item [dict keys $request] { if {[string tolower $item] eq [string tolower $field]} { return $item } } return $field } method request {subcommand args} { my variable request switch $subcommand { dump { return $request } field { tailcall my RequestFind [lindex $args 0] } get { set field [my RequestFind [lindex $args 0]] if {![dict exists $request $field]} { return {} } tailcall dict get $request $field } getnull { set field [my RequestFind [lindex $args 0]] if {![dict exists $request $field]} { return {} } tailcall dict get $request $field } exists { set field [my RequestFind [lindex $args 0]] tailcall dict exists $request $field } parse { if {[catch {my MimeParse [lindex $args 0]} result]} { my error 400 $result tailcall my DoOutput } set request $result } replace { set request [lindex $args 0] } set { dict set request {*}$args } default { error "Unknown command $subcommand. Valid: field, get, getnull, exists, parse, replace, set" } } } method reply {subcommand args} { my variable reply switch $subcommand { dump { return $reply } exists { return [dict exists $reply {*}$args] } get - getnull { return [dict getnull $reply {*}$args] } replace { set reply [my HttpHeaders_Default] if {[llength $args]==1} { foreach {f v} [lindex $args 0] { dict set reply $f $v } } else { foreach {f v} $args { dict set reply $f $v } } } output { set result {} if {![dict exists $reply Status]} { set status {200 OK} } else { set status [dict get $reply Status] } set result "[my EncodeStatus $status]\n" foreach {f v} $reply { if {$f in {Status}} continue append result "[string trimright $f :]: $v\n" } #append result \n return $result } set { dict set reply {*}$args } default { error "Unknown command $subcommand. Valid: exists, get, getnull, output, replace, set" } } } # 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. method reset {} { my variable reply_body my reply replace [my HttpHeaders_Default] my reply set Server [my <server> clay get server/ string] my reply set Date [my timestamp] set reply_body {} } # 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. method timeOutCheck {} { my variable dispatched_time if {([clock seconds]-$dispatched_time)>120} { ### # Something has lasted over 2 minutes. Kill this ### catch { my error 408 {Request Timed out} my DoOutput } } } ### # Return the current system time in the format: [example {%a, %d %b %Y %T %Z}] ### method timestamp {} { return [clock format [clock seconds] -format {%a, %d %b %Y %T %Z}] } } |
Changes to modules/httpd/build/scgi.tcl.
1 2 3 | ### # Return data from an SCGI process ### | > > > > > > > | > | | | > | < > < < < < < < < | | | | | < < < < < < | < < < < < | | | | | > > | > | > < < | < < | < | | | | | | | > > | | | < | > > > | | < < < < < < < < < < < < < < < < < < < < | < < > | < < < | < | | | | | | | < > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | ### # Return data from an SCGI process ### ::clay::define ::httpd::protocol.scgi { method EncodeStatus {status} { return "Status: $status" } } ::clay::define ::httpd::content.scgi { superclass ::httpd::content.proxy method scgi_info {} { ### # This method should check if a process is launched # or launch it if needed, and return a list of # HOST PORT SCRIPT_NAME ### # return {localhost 8016 /some/path} error unimplemented } method proxy_channel {} { set sockinfo [my scgi_info] if {$sockinfo eq {}} { my error 404 {Not Found} tailcall my DoOutput } lassign $sockinfo scgihost scgiport scgiscript my clay set SCRIPT_NAME $scgiscript if {![string is integer $scgiport]} { my error 404 {Not Found} tailcall my DoOutput } return [::socket $scgihost $scgiport] } method ProxyRequest {chana chanb} { chan event $chanb writable {} my log ProxyRequest {} chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 set info [dict create CONTENT_LENGTH 0 SCGI 1.0 SCRIPT_NAME [my clay get SCRIPT_NAME]] foreach {f v} [my request dump] { dict set info $f $v } set length [dict get $info CONTENT_LENGTH] set block {} foreach {f v} $info { append block [string toupper $f] \x00 $v \x00 } chan puts -nonewline $chanb "[string length $block]:$block," # Light off another coroutine #set cmd [list coroutine [my CoroName] {*}[namespace code [list my ProxyReply $chanb $chana]]] if {$length} { chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 ### # Send any POST/PUT/etc content ### my ChannelCopy $chana $chanb -size $length #chan copy $chana $chanb -size $length -command [info coroutine] } else { chan flush $chanb } chan event $chanb readable [info coroutine] yield } method ProxyReply {chana chanb args} { my log ProxyReply [list args $args] chan event $chana readable {} set replyhead [my HttpHeaders $chana] set replydat [my MimeParse $replyhead] ### # Convert the Status: header from the CGI process to # a standard service reply line from a web server, but # otherwise spit out the rest of the headers verbatim ### set replybuffer "HTTP/1.0 [dict get $replydat Status]\n" append replybuffer $replyhead chan configure $chanb -translation {auto crlf} -blocking 0 -buffering full -buffersize 4096 chan puts $chanb $replybuffer ### # Output the body. With no -size flag, channel will copy until EOF ### chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 my ChannelCopy $chana $chanb -chunk 4096 } } ### # Act as an SCGI Server ### ::clay::define ::httpd::server.scgi { superclass ::httpd::server clay set socket/ buffersize 32768 clay set socket/ blocking 0 clay set socket/ translation {binary binary} method debug args { puts $args } method Connect {uuid sock ip} { yield [info coroutine] chan event $sock readable {} chan configure $sock \ -blocking 1 \ -translation {binary binary} \ -buffersize 4096 \ -buffering none my counter url_hit try { # Read the SCGI request on byte at a time until we reach a ":" dict set query http HTTP_HOST {} dict set query http CONTENT_LENGTH 0 dict set query http REQUEST_URI / dict set query http REMOTE_ADDR $ip set size {} while 1 { set char [::coroutine::util::read $sock 1] if {[chan eof $sock]} { catch {close $sock} return } if {$char eq ":"} break append size $char } # With length in hand, read the netstring encoded headers set inbuffer [::coroutine::util::read $sock [expr {$size+1}]] chan configure $sock -blocking 0 -buffersize 4096 -buffering full foreach {f v} [lrange [split [string range $inbuffer 0 end-1] \0] 0 end-1] { dict set query http $f $v } if {![dict exists $query http REQUEST_PATH]} { set uri [dict get $query http REQUEST_URI] set uriinfo [::uri::split $uri] dict set query http REQUEST_PATH [dict get $uriinfo path] } set reply [my dispatch $query] } on error {err errdat} { my debug [list uri: [dict getnull $query http REQUEST_URI] ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] my log BadRequest $uuid [list ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] catch {chan puts $sock "HTTP/1.0 400 Bad Request (The data is invalid)"} catch {chan event readable $sock {}} catch {chan event writeable $sock {}} catch {chan close $sock} return } if {[dict size $reply]==0} { my log BadLocation $uuid $query dict set query http HTTP_STATUS 404 dict set query template notfound dict set query mixin reply ::httpd::content.template } try { set pageobj [::httpd::reply create ::httpd::object::$uuid [self]] dict set reply mixin protocol ::httpd::protocol.scgi $pageobj dispatch $sock $reply } on error {err errdat} { my debug [list ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] my log BadRequest $uuid [list ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] catch {$pageobj destroy} catch {chan event readable $sock {}} catch {chan event writeable $sock {}} catch {chan close $sock} return } } } |
Deleted modules/httpd/build/server.man.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to modules/httpd/build/server.tcl.
1 | ### | | < > > > | | | | | | | | > | | | | | | | > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < | < < < < < < < < < < < < | < < < < < < < | | < < | < | | | | | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | | | < > > | > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > | | | > > > > > > | > | > | | | | > > > > | | | | > > > | > > > > > > > > > | | | | | | | | | | > > > > > > > > > > > | | | > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | ### # 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. ### namespace eval ::httpd::object {} namespace eval ::httpd::coro {} ::clay::define ::httpd::server { superclass ::httpd::mime clay set server/ port auto clay set server/ myaddr 127.0.0.1 clay set server/ string [list TclHttpd $::httpd::version] clay set server/ name [info hostname] clay set server/ doc_root {} clay set server/ reverse_dns 0 clay set server/ configuration_file {} clay set server/ protocol {HTTP/1.1} clay set socket/ buffersize 32768 clay set socket/ translation {auto crlf} clay set reply_class ::httpd::reply Array template Dict url_patterns {} constructor { {args { port {default auto comment {Port to listen on}} myaddr {default 127.0.0.1 comment {IP address to listen on. "all" means all}} string {default auto comment {Value for SERVER_SOFTWARE in HTTP headers}} name {default auto comment {Value for SERVER_NAME in HTTP headers. Defaults to [info hostname]}} doc_root {default {} comment {File path to serve.}} reverse_dns {default 0 comment {Perform reverse DNS to convert IPs into hostnames}} configuration_file {default {} comment {Configuration file to load into server namespace}} protocol {default {HTTP/1.1} comment {Value for SERVER_PROTOCOL in HTTP headers}} }}} { if {[llength $args]==1} { set arglist [lindex $args 0] } else { set arglist $args } foreach {var val} $arglist { my clay set server/ $var $val } my start } destructor { my stop } ### # 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. ### method connect {sock ip port} { ### # If an IP address is blocked drop the # connection ### if {[my Validate_Connection $sock $ip]} { catch {close $sock} return } set uuid [my Uuid_Generate] set coro [coroutine ::httpd::coro::$uuid {*}[namespace code [list my Connect $uuid $sock $ip]]] chan event $sock readable $coro } method ServerHeaders {ip http_request mimetxt} { set result {} dict set result HTTP_HOST {} dict set result CONTENT_LENGTH 0 foreach {f v} [my MimeParse $mimetxt] { set fld [string toupper [string map {- _} $f]] if {$fld in {CONTENT_LENGTH CONTENT_TYPE}} { set qfld $fld } else { set qfld HTTP_$fld } dict set result $qfld $v } dict set result REMOTE_ADDR $ip dict set result REMOTE_HOST [my HostName $ip] dict set result REQUEST_METHOD [lindex $http_request 0] set uriinfo [::uri::split [lindex $http_request 1]] dict set result uriinfo $uriinfo dict set result REQUEST_URI [lindex $http_request 1] dict set result REQUEST_PATH [dict get $uriinfo path] dict set result REQUEST_VERSION [lindex [split [lindex $http_request end] /] end] dict set result DOCUMENT_ROOT [my clay get server/ doc_root] dict set result QUERY_STRING [dict get $uriinfo query] dict set result REQUEST_RAW $http_request dict set result SERVER_PORT [my port_listening] dict set result SERVER_NAME [my clay get server/ name] dict set result SERVER_PROTOCOL [my clay get server/ protocol] dict set result SERVER_SOFTWARE [my clay get server/ string] if {[string match 127.* $ip]} { dict set result LOCALHOST [expr {[lindex [split [dict getnull $result HTTP_HOST] :] 0] eq "localhost"}] } return $result } ### # 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. ### method Connect {uuid sock ip} { yield [info coroutine] chan event $sock readable {} chan configure $sock \ -blocking 0 \ -translation {auto crlf} \ -buffering line my counter url_hit try { set readCount [::coroutine::util::gets_safety $sock 4096 http_request] set mimetxt [my HttpHeaders $sock] dict set query UUID $uuid dict set query mimetxt $mimetxt dict set query mixin style [my clay get server/ style] dict set query http [my ServerHeaders $ip $http_request $mimetxt] my Headers_Process query set reply [my dispatch $query] } on error {err errdat} { my debug [list uri: [dict getnull $query REQUEST_URI] ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] my log BadRequest $uuid [list ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] catch {chan puts $sock "HTTP/1.0 400 Bad Request (The data is invalid)"} catch {chan close $sock} return } if {[dict size $reply]==0} { set reply $query my log BadLocation $uuid $query dict set reply http HTTP_STATUS {404 Not Found} dict set reply template notfound dict set reply mixin reply ::httpd::content.template } set pageobj [::httpd::reply create ::httpd::object::$uuid [self]] tailcall $pageobj dispatch $sock $reply } # Increment an internal counter. method counter which { my variable counters incr counters($which) } ### # Check open connections for a time out event. ### method CheckTimeout {} { foreach obj [info commands ::httpd::object::*] { try { $obj timeOutCheck } on error {} { catch {$obj destroy} } } } method debug args {} ### # Given a key/value list of information, return a data structure describing how # the server should reply. ### method dispatch {data} { set reply [my Dispatch_Local $data] if {[dict size $reply]} { return $reply } return [my Dispatch_Default $data] } ### # 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. ### method Dispatch_Default {reply} { ### # Fallback to docroot handling ### set doc_root [dict getnull $reply http DOCUMENT_ROOT] if {$doc_root ne {}} { ### # Fall back to doc_root handling ### dict set reply prefix {} dict set reply path $doc_root dict set reply mixin reply httpd::content.file return $reply } return {} } ### # 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. ### method Dispatch_Local data {} ### # 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. ### method Headers_Local {varname} {} ### # Introspect and possibly modify a data structure destined for a reply. This # method is built dynamically by the [cmd plugin] method. ### method Headers_Process varname {} ### # 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. ### method HostName ipaddr { if {![my clay get server/ reverse_dns]} { return $ipaddr } set t [::dns::resolve $ipaddr] set result [::dns::name $t] ::dns::cleanup $t return $result } ### # 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. ### method log args { # Do nothing for now } ### # 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. ### method plugin {slot {class {}}} { if {$class eq {}} { set class ::httpd::plugin.$slot } if {[info command $class] eq {}} { error "Class $class for plugin $slot does not exist" } my clay mixinmap $slot $class set mixinmap [my clay get mixin] ### # Perform action on load ### set script [$class clay search plugin/ load] eval $script ### # rebuild the dispatch method ### set body "\n try \{" append body \n { set reply [my Dispatch_Local $data] if {[dict size $reply]} {return $reply} } foreach {slot class} $mixinmap { set script [$class clay search plugin/ dispatch] if {[string length $script]} { append body \n "# SLOT $slot" append body \n $script } } append body \n { return [my Dispatch_Default $data]} append body \n "\} on error \{err errdat\} \{" append body \n { puts [list DISPATCH ERROR [dict get $errdat -errorinfo]] ; return {}} append body \n "\}" oo::objdefine [self] method dispatch data $body ### # rebuild the Headers_Process method ### set body "\n try \{" append body \n " upvar 1 \$varname query" append body \n { my Headers_Local query} foreach {slot class} $mixinmap { set script [$class clay search plugin/ headers] if {[string length $script]} { append body \n "# SLOT $slot" append body \n $script } } append body \n "\} on error \{err errdat\} \{" append body \n { puts [list HEADERS ERROR [dict get $errdat -errorinfo]] ; return {}} append body \n "\}" oo::objdefine [self] method Headers_Process varname $body ### # rebuild the Threads_Start method ### set body "\n try \{" foreach {slot class} $mixinmap { set script [$class clay search plugin/ thread] if {[string length $script]} { append body \n "# SLOT $slot" append body \n $script } } append body \n "\} on error \{err errdat\} \{" append body \n { puts [list THREAD START ERROR [dict get $errdat -errorinfo]] ; return {}} append body \n "\}" oo::objdefine [self] method Thread_start {} $body } # Return the actual port that httpd is listening on. method port_listening {} { my variable port_listening return $port_listening } # 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. method PrefixNormalize prefix { set prefix [string trimright $prefix /] set prefix [string trimright $prefix *] set prefix [string trimright $prefix /] return $prefix } method source {filename} { source $filename } # Open the socket listener. method start {} { # Build a namespace to contain replies namespace eval [namespace current]::reply {} my variable socklist port_listening if {[my clay get server/ configuration_file] ne {}} { source [my clay get server/ configuration_file] } set port [my clay get server/ port] if { $port in {auto {}} } { package require nettool set port [::nettool::allocate_port 8015] } set port_listening $port set myaddr [my clay get server/ myaddr] my debug [list [self] listening on $port $myaddr] if {$myaddr ni {all any * {}}} { foreach ip $myaddr { lappend socklist [socket -server [namespace code [list my connect]] -myaddr $ip $port] } } else { lappend socklist [socket -server [namespace code [list my connect]] $port] } ::cron::every [self] 120 [namespace code {my CheckTimeout}] my Thread_start } # Shut off the socket listener, and destroy any pending replies. method stop {} { my variable socklist if {[info exists socklist]} { foreach sock $socklist { catch {close $sock} } } set socklist {} ::cron::cancel [self] } Ensemble SubObject::db {} { return [namespace current]::Sqlite_db } Ensemble SubObject::default {} { return [namespace current]::$method } # Return a template for the string [arg page] method template page { my variable template if {[info exists template($page)]} { return $template($page) } set template($page) [my TemplateSearch $page] return $template($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. method TemplateSearch page { set doc_root [my clay get server/ doc_root] if {$doc_root ne {} && [file exists [file join $doc_root $page.tml]]} { return [::fileutil::cat [file join $doc_root $page.tml]] } if {$doc_root ne {} && [file exists [file join $doc_root $page.html]]} { return [::fileutil::cat [file join $doc_root $page.html]] } switch $page { redirect { return { [my html_header "$HTTP_STATUS"] The page you are looking for: <b>[my request get REQUEST_URI]</b> has moved. <p> If your browser does not automatically load the new location, it is <a href=\"$msg\">$msg</a> [my html_footer] } } internal_error { return { [my html_header "$HTTP_STATUS"] Error serving <b>[my request get REQUEST_URI]</b>: <p> The server encountered an internal server error: <pre>$msg</pre> <pre><code> $errorInfo </code></pre> [my html_footer] } } notfound { return { [my html_header "$HTTP_STATUS"] The page you are looking for: <b>[my request get REQUEST_URI]</b> does not exist. [my html_footer] } } } } ### # Built by the [cmd plugin] method. Called by the [cmd start] method. Intended # to allow plugins to spawn worker threads. ### method Thread_start {} {} ### # Generate a GUUID. Used to ensure every request has a unique ID. # The default implementation is: # [example { # return [::uuid::uuid generate] # }] ### method Uuid_Generate {} { return [::uuid::uuid generate] } ### # 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. ### method Validate_Connection {sock ip} { return 0 } } ### # Provide a backward compadible alias ### ::clay::define ::httpd::server::dispatch { superclass ::httpd::server } |
Changes to modules/httpd/build/websocket.tcl.
1 2 3 | ### # Upgrade a connection to a websocket ### | | | 1 2 3 4 5 6 | ### # Upgrade a connection to a websocket ### ::clay::define ::httpd::content.websocket { } |
Changes to modules/httpd/httpd.man.
|
| | | | < < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [vset VERSION 4.3] [comment {-*- tcl -*- doctools manpage}] [manpage_begin httpd n [vset VERSION]] [keywords WWW] [copyright {2018 Sean Woods <[email protected]>}] [moddesc {Tcl Web Server}] [titledesc {A TclOO and coroutine based web server}] [category Networking] [keywords TclOO] [keywords http] [keywords httpd] [keywords httpserver] [keywords services] [require Tcl 8.6] [require httpd [opt [vset VERSION]]] [require uuid] [require clay] [require coroutine] [require fileutil] [require fileutil::magic::filetype] [require websocket] [require mime] [require cron] [require uri] |
︙ | ︙ | |||
38 39 40 41 42 43 44 | [section {Minimal Example}] Starting a web service requires starting a class of type [cmd httpd::server], and providing that server with one or more URIs to service, and [cmd httpd::reply] derived classes to generate them. [example { | | | | | | > | > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 | [section {Minimal Example}] Starting a web service requires starting a class of type [cmd httpd::server], and providing that server with one or more URIs to service, and [cmd httpd::reply] derived classes to generate them. [example { oo::class create ::reply.hello { method content {} { my puts "<HTML><HEAD><TITLE>IRM Dispatch Server</TITLE></HEAD><BODY>" my puts "<h1>Hello World!</h1>" my puts </BODY></HTML> } } ::httpd::server create HTTPD port 8015 myaddr 127.0.0.1 doc_root ~/htdocs HTTPD plugin dispatch httpd::server::dispatch HTTPD uri add * /hello [list mixin reply.hello] }] The bare module does have facilities to hose a files from a file system. Files that end in a .tml will be substituted in the style of Tclhttpd: [example { <!-- hello.tml --> [my html_header {Hello World!}] Your Server is running. <p> The time is now [clock format [clock seconds]] [my html_footer] }] A complete example of an httpd server is in the /examples directory of Tcllib. It also show how to dispatch URIs to other processes via SCGI and HTTP proxies. [example { cd ~/tcl/sandbox/tcllib tclsh examples/httpd.tcl }] [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] 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] } } }] [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.
1 2 3 4 5 6 | ### # Amalgamated package for httpd # Do not edit directly, tweak the source in src/ and rerun # build.tcl ### package require Tcl 8.6 | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | ### # Amalgamated package for httpd # Do not edit directly, tweak the source in src/ and rerun # build.tcl ### package require Tcl 8.6 package provide httpd 4.3 namespace eval ::httpd {} set ::httpd::version 4.3 ### # START: core.tcl ### ### # Author: Sean Woods, [email protected] ## # 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 ### package require uri package require dns package require cron package require coroutine package require clay 0.3 package require mime package require fileutil package require websocket package require Markdown package require uuid package require fileutil::magic::filetype namespace eval httpd::content {} namespace eval ::url {} namespace eval ::httpd {} namespace eval ::scgi {} clay::define ::httpd::mime { method ChannelCopy {in out args} { set chunk 4096 set size -1 foreach {f v} $args { set [string trim $f -] $v } dict set info coroutine [info coroutine] if {$size>0 && $chunk>$size} { set chunk $size } set bytes 0 set sofar 0 set method [self method] while 1 { set command {} set error {} if {$size>=0} { incr sofar $bytes set remaining [expr {$size-$sofar}] if {$remaining <= 0} { break } elseif {$chunk > $remaining} { set chunk $remaining } } lassign [yieldto chan copy $in $out -size $chunk \ -command [list [info coroutine] $method]] \ command bytes error if {$command ne $method} { error "Subroutine $method interrupted" } if {[string length $error]} { error $error } if {[chan eof $in]} { break } } } method html_header {{title {}} args} { set result {} append result "<HTML><HEAD>" if {$title ne {}} { append result "<TITLE>$title</TITLE>" |
︙ | ︙ | |||
118 119 120 121 122 123 124 125 126 | method HttpHeaders_Default {} { return {Status {200 OK} Content-Size 0 Content-Type {text/html; charset=UTF-8} Cache-Control {no-cache} Connection close} } ### | > > > > > > > > > > < > > > | 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 | method HttpHeaders_Default {} { return {Status {200 OK} Content-Size 0 Content-Type {text/html; charset=UTF-8} Cache-Control {no-cache} Connection close} } method HttpServerHeaders {} { return { CONTENT_LENGTH CONTENT_TYPE QUERY_STRING REMOTE_USER AUTH_TYPE REQUEST_METHOD REMOTE_ADDR REMOTE_HOST REQUEST_URI REQUEST_PATH REQUEST_VERSION DOCUMENT_ROOT QUERY_STRING REQUEST_RAW GATEWAY_INTERFACE SERVER_PORT SERVER_HTTPS_PORT SERVER_NAME SERVER_SOFTWARE SERVER_PROTOCOL } } ### # 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. ### method MimeParse mimetext { set data(mimeorder) {} foreach line [split $mimetext \n] { # This regexp picks up # key: value # MIME headers. MIME headers may be continue with a line |
︙ | ︙ | |||
206 207 208 209 210 211 212 213 214 215 216 217 218 219 | } } dict set result $ckey $data(mime,$key) } return $result } method Url_Decode data { regsub -all {\+} $data " " data regsub -all {([][$\\])} $data {\\\1} data regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data {[format %c 0x\1]} data return [subst $data] } | > | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | } } dict set result $ckey $data(mime,$key) } return $result } # De-httpizes a string. method Url_Decode data { regsub -all {\+} $data " " data regsub -all {([][$\\])} $data {\\\1} data regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data {[format %c 0x\1]} data return [subst $data] } |
︙ | ︙ | |||
267 268 269 270 271 272 273 | ### # END: core.tcl ### ### # START: reply.tcl ### ### | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > | | | > > > > > > | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | | > > > | > | | | > | | < | > > > | > | < > > > > > > | 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 | ### # END: core.tcl ### ### # START: reply.tcl ### ### # 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] # # 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] # } # } # # }] ### ::clay::define ::httpd::reply { superclass ::httpd::mime Variable transfer_complete 0 Dict reply {} Dict request { CONTENT_LENGTH 0 COOKIE {} HTTP_HOST {} REFERER {} REQUEST_URI {} REMOTE_ADDR {} REMOTE_HOST {} USER_AGENT {} SESSION {} } constructor {ServerObj args} { my variable chan dispatched_time uuid set uuid [namespace tail [self]] set dispatched_time [clock milliseconds] my clay delegate <server> $ServerObj foreach {field value} [::clay::args_to_options {*}$args] { my clay set config $field: $value } } ### # clean up on exit ### destructor { my close } ### # Close channels opened by this object ### method close {} { my variable chan if {[info exists chan] && $chan ne {}} { catch {chan event $chan readable {}} catch {chan event $chan writable {}} catch {chan flush $chan} catch {chan close $chan} set chan {} } } ### # Record a dispatch event ### method Log_Dispatched {} { my log Dispatched [dict create \ REMOTE_ADDR [my request get REMOTE_ADDR] \ REMOTE_HOST [my request get REMOTE_HOST] \ COOKIE [my request get HTTP_COOKIE] \ REFERER [my request get HTTP_REFERER] \ USER_AGENT [my request get HTTP_USER_AGENT] \ REQUEST_URI [my request get REQUEST_URI] \ 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 if {[dict exists $datastate mixin]} { set mixinmap [dict get $datastate mixin] } else { set mixinmap {} } foreach item [dict keys $datastate MIXIN_*] { set slot [string range $item 6 end] dict set mixinmap [string tolower $slot] [dict get $datastate $item] } my clay mixinmap {*}$mixinmap if {[dict exists $datastate delegate]} { my clay delegate {*}[dict get $datastate delegate] } my reset set request [my clay get dict/ request] foreach {f v} $datastate { if {[string index $f end] eq "/"} { my clay merge $f $v } else { my clay set $f $v } if {$f eq "http"} { foreach {ff vf} $v { dict set request $ff $vf } } } my Session_Load my Log_Dispatched my Dispatch } on error {err errdat} { my error 500 $err [dict get $errdat -errorinfo] my DoOutput } } method Dispatch {} { # Invoke the URL implementation. my content my DoOutput } method html_css {} { set result "<link rel=\"stylesheet\" href=\"/style.css\">" append result \n {<style media="screen" type="text/css"> body { background: url(images/etoyoc-circuit-tile.gif) repeat; |
︙ | ︙ | |||
373 374 375 376 377 378 379 | } method html_footer {args} { set result {</div><div id="footer">} append result {</div></BODY></HTML>} } | < < < < < < < < < < < < < | | < | > > > | | | | 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 | } method html_footer {args} { set result {</div><div id="footer">} append result {</div></BODY></HTML>} } method error {code {msg {}} {errorInfo {}}} { my clay set HTTP_ERROR $code my reset set qheaders [my clay dump] set HTTP_STATUS "$code [my http_code_string $code]" dict with qheaders {} my reply replace {} my reply set Status $HTTP_STATUS my reply set Content-Type {text/html; charset=UTF-8} switch $code { 301 - 302 - 303 - 307 - 308 { my reply set Location $msg set template [my <server> template redirect] } 404 { set template [my <server> template notfound] } default { set template [my <server> template internal_error] } } my puts [subst $template] } ### # 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" ### method content {} { my puts [my html_header {Hello World!}] my puts "<H1>HELLO WORLD!</H1>" my puts [my html_footer] } ### # Formulate a standard HTTP status header from he string provided. ### method EncodeStatus {status} { return "HTTP/1.0 $status" } method log {type {info {}}} { my variable dispatched_time uuid my <server> log $type $uuid $info } method CoroName {} { if {[info coroutine] eq {}} { return ::httpd::object::[my clay get UUID] } } ### # Generates the the HTTP reply, streams that reply back across [arg chan], # and destroys the object. ### method DoOutput {} { my variable reply_body chan if {$chan eq {}} return catch { my wait writable $chan chan configure $chan -translation {binary binary} |
︙ | ︙ | |||
467 468 469 470 471 472 473 474 475 476 477 478 479 | } chan puts -nonewline $chan $result my log HttpAccess {} } my destroy } method FormData {} { my variable chan formdata # Run this only once if {[info exists formdata]} { return $formdata } | > > > > > > > > > < < < | < | | | 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 | } chan puts -nonewline $chan $result my log HttpAccess {} } my destroy } ### # 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. ### method FormData {} { my variable chan formdata # Run this only once if {[info exists formdata]} { return $formdata } set length [my request get CONTENT_LENGTH] set formdata {} if {[my request get REQUEST_METHOD] in {"POST" "PUSH"}} { set rawtype [my request get CONTENT_TYPE] if {[string toupper [string range $rawtype 0 8]] ne "MULTIPART"} { set type $rawtype } else { set type multipart } switch $type { multipart { ### # Ok, Multipart MIME is troublesome, farm out the parsing to a dedicated tool ### set body [my clay get mimetxt] append body \n [my PostData $length] set token [::mime::initialize -string $body] foreach item [::mime::getheader $token -names] { dict set formdata $item [::mime::getheader $token $item] } foreach item {content encoding params parts size} { dict set formdata MIME_[string toupper $item] [::mime::getproperty $token $item] |
︙ | ︙ | |||
515 516 517 518 519 520 521 | foreach {name value} [split $pair "="] { lappend formdata [my Url_Decode $name] [my Url_Decode $value] } } } } } else { | | > > | > > > > > > > > > > > > > > > > > > > > > > > > < | | > | > > > > | | | | | | | | | | | | | | | | | < | | | | | | | | | | | > > | > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | > > | > > | | > | < < > > | | | | > | | < > > > | | | | | | | | > | | | | | | | > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < | < < < < < < < < < < < < | < < < < < < < | | < < | < | | | | | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | | | < > > | > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > | | | > > > > > > | > | > | | | | > > > > | | | | > > > | > > > > > > > > > | | | | | | | | | | > > > > > > > > > > > | | | > > | | | | | | | | | < < < < < | | | | | | | | | | | | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 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 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 | foreach {name value} [split $pair "="] { lappend formdata [my Url_Decode $name] [my Url_Decode $value] } } } } } else { foreach pair [split [my clay get QUERY_STRING] "&"] { foreach {name value} [split $pair "="] { lappend formdata [my Url_Decode $name] [my Url_Decode $value] } } } return $formdata } # Stream [arg length] bytes from the [arg chan] socket, but only of the request is a # POST or PUSH. Returns an empty string otherwise. method PostData {length} { my variable postdata # Run this only once if {[info exists postdata]} { return $postdata } set postdata {} if {[my request get REQUEST_METHOD] in {"POST" "PUSH"}} { my variable chan chan configure $chan -translation binary -blocking 0 -buffering full -buffersize 4096 set postdata [::coroutine::util::read $chan $length] } return $postdata } # Manage session data method Session_Load {} {} # 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 # }] method TransferComplete args { my variable chan transfer_complete set transfer_complete 1 my log TransferComplete set chan {} foreach c $args { catch {chan event $c readable {}} catch {chan event $c writable {}} catch {chan flush $c} catch {chan close $c} } my destroy } # Appends the value of [arg string] to the end of [arg reply_body], as well as a trailing newline # character. method puts line { my variable reply_body append reply_body $line \n } method RequestFind {field} { my variable request if {[dict exists $request $field]} { return $field } foreach item [dict keys $request] { if {[string tolower $item] eq [string tolower $field]} { return $item } } return $field } method request {subcommand args} { my variable request switch $subcommand { dump { return $request } field { tailcall my RequestFind [lindex $args 0] } get { set field [my RequestFind [lindex $args 0]] if {![dict exists $request $field]} { return {} } tailcall dict get $request $field } getnull { set field [my RequestFind [lindex $args 0]] if {![dict exists $request $field]} { return {} } tailcall dict get $request $field } exists { set field [my RequestFind [lindex $args 0]] tailcall dict exists $request $field } parse { if {[catch {my MimeParse [lindex $args 0]} result]} { my error 400 $result tailcall my DoOutput } set request $result } replace { set request [lindex $args 0] } set { dict set request {*}$args } default { error "Unknown command $subcommand. Valid: field, get, getnull, exists, parse, replace, set" } } } method reply {subcommand args} { my variable reply switch $subcommand { dump { return $reply } exists { return [dict exists $reply {*}$args] } get - getnull { return [dict getnull $reply {*}$args] } replace { set reply [my HttpHeaders_Default] if {[llength $args]==1} { foreach {f v} [lindex $args 0] { dict set reply $f $v } } else { foreach {f v} $args { dict set reply $f $v } } } output { set result {} if {![dict exists $reply Status]} { set status {200 OK} } else { set status [dict get $reply Status] } set result "[my EncodeStatus $status]\n" foreach {f v} $reply { if {$f in {Status}} continue append result "[string trimright $f :]: $v\n" } #append result \n return $result } set { dict set reply {*}$args } default { error "Unknown command $subcommand. Valid: exists, get, getnull, output, replace, set" } } } # 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. method reset {} { my variable reply_body my reply replace [my HttpHeaders_Default] my reply set Server [my <server> clay get server/ string] my reply set Date [my timestamp] set reply_body {} } # 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. method timeOutCheck {} { my variable dispatched_time if {([clock seconds]-$dispatched_time)>120} { ### # Something has lasted over 2 minutes. Kill this ### catch { my error 408 {Request Timed out} my DoOutput } } } ### # Return the current system time in the format: [example {%a, %d %b %Y %T %Z}] ### method timestamp {} { return [clock format [clock seconds] -format {%a, %d %b %Y %T %Z}] } } ### # END: reply.tcl ### ### # START: server.tcl ### ### # 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. ### namespace eval ::httpd::object {} namespace eval ::httpd::coro {} ::clay::define ::httpd::server { superclass ::httpd::mime clay set server/ port auto clay set server/ myaddr 127.0.0.1 clay set server/ string [list TclHttpd $::httpd::version] clay set server/ name [info hostname] clay set server/ doc_root {} clay set server/ reverse_dns 0 clay set server/ configuration_file {} clay set server/ protocol {HTTP/1.1} clay set socket/ buffersize 32768 clay set socket/ translation {auto crlf} clay set reply_class ::httpd::reply Array template Dict url_patterns {} constructor { {args { port {default auto comment {Port to listen on}} myaddr {default 127.0.0.1 comment {IP address to listen on. "all" means all}} string {default auto comment {Value for SERVER_SOFTWARE in HTTP headers}} name {default auto comment {Value for SERVER_NAME in HTTP headers. Defaults to [info hostname]}} doc_root {default {} comment {File path to serve.}} reverse_dns {default 0 comment {Perform reverse DNS to convert IPs into hostnames}} configuration_file {default {} comment {Configuration file to load into server namespace}} protocol {default {HTTP/1.1} comment {Value for SERVER_PROTOCOL in HTTP headers}} }}} { if {[llength $args]==1} { set arglist [lindex $args 0] } else { set arglist $args } foreach {var val} $arglist { my clay set server/ $var $val } my start } destructor { my stop } ### # 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. ### method connect {sock ip port} { ### # If an IP address is blocked drop the # connection ### if {[my Validate_Connection $sock $ip]} { catch {close $sock} return } set uuid [my Uuid_Generate] set coro [coroutine ::httpd::coro::$uuid {*}[namespace code [list my Connect $uuid $sock $ip]]] chan event $sock readable $coro } method ServerHeaders {ip http_request mimetxt} { set result {} dict set result HTTP_HOST {} dict set result CONTENT_LENGTH 0 foreach {f v} [my MimeParse $mimetxt] { set fld [string toupper [string map {- _} $f]] if {$fld in {CONTENT_LENGTH CONTENT_TYPE}} { set qfld $fld } else { set qfld HTTP_$fld } dict set result $qfld $v } dict set result REMOTE_ADDR $ip dict set result REMOTE_HOST [my HostName $ip] dict set result REQUEST_METHOD [lindex $http_request 0] set uriinfo [::uri::split [lindex $http_request 1]] dict set result uriinfo $uriinfo dict set result REQUEST_URI [lindex $http_request 1] dict set result REQUEST_PATH [dict get $uriinfo path] dict set result REQUEST_VERSION [lindex [split [lindex $http_request end] /] end] dict set result DOCUMENT_ROOT [my clay get server/ doc_root] dict set result QUERY_STRING [dict get $uriinfo query] dict set result REQUEST_RAW $http_request dict set result SERVER_PORT [my port_listening] dict set result SERVER_NAME [my clay get server/ name] dict set result SERVER_PROTOCOL [my clay get server/ protocol] dict set result SERVER_SOFTWARE [my clay get server/ string] if {[string match 127.* $ip]} { dict set result LOCALHOST [expr {[lindex [split [dict getnull $result HTTP_HOST] :] 0] eq "localhost"}] } return $result } ### # 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. ### method Connect {uuid sock ip} { yield [info coroutine] chan event $sock readable {} chan configure $sock \ -blocking 0 \ -translation {auto crlf} \ -buffering line my counter url_hit try { set readCount [::coroutine::util::gets_safety $sock 4096 http_request] set mimetxt [my HttpHeaders $sock] dict set query UUID $uuid dict set query mimetxt $mimetxt dict set query mixin style [my clay get server/ style] dict set query http [my ServerHeaders $ip $http_request $mimetxt] my Headers_Process query set reply [my dispatch $query] } on error {err errdat} { my debug [list uri: [dict getnull $query REQUEST_URI] ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] my log BadRequest $uuid [list ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] catch {chan puts $sock "HTTP/1.0 400 Bad Request (The data is invalid)"} catch {chan close $sock} return } if {[dict size $reply]==0} { set reply $query my log BadLocation $uuid $query dict set reply http HTTP_STATUS {404 Not Found} dict set reply template notfound dict set reply mixin reply ::httpd::content.template } set pageobj [::httpd::reply create ::httpd::object::$uuid [self]] tailcall $pageobj dispatch $sock $reply } # Increment an internal counter. method counter which { my variable counters incr counters($which) } ### # Check open connections for a time out event. ### method CheckTimeout {} { foreach obj [info commands ::httpd::object::*] { try { $obj timeOutCheck } on error {} { catch {$obj destroy} } } } method debug args {} ### # Given a key/value list of information, return a data structure describing how # the server should reply. ### method dispatch {data} { set reply [my Dispatch_Local $data] if {[dict size $reply]} { return $reply } return [my Dispatch_Default $data] } ### # 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. ### method Dispatch_Default {reply} { ### # Fallback to docroot handling ### set doc_root [dict getnull $reply http DOCUMENT_ROOT] if {$doc_root ne {}} { ### # Fall back to doc_root handling ### dict set reply prefix {} dict set reply path $doc_root dict set reply mixin reply httpd::content.file return $reply } return {} } ### # 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. ### method Dispatch_Local data {} ### # 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. ### method Headers_Local {varname} {} ### # Introspect and possibly modify a data structure destined for a reply. This # method is built dynamically by the [cmd plugin] method. ### method Headers_Process varname {} ### # 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. ### method HostName ipaddr { if {![my clay get server/ reverse_dns]} { return $ipaddr } set t [::dns::resolve $ipaddr] set result [::dns::name $t] ::dns::cleanup $t return $result } ### # 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. ### method log args { # Do nothing for now } ### # 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. ### method plugin {slot {class {}}} { if {$class eq {}} { set class ::httpd::plugin.$slot } if {[info command $class] eq {}} { error "Class $class for plugin $slot does not exist" } my clay mixinmap $slot $class set mixinmap [my clay get mixin] ### # Perform action on load ### set script [$class clay search plugin/ load] eval $script ### # rebuild the dispatch method ### set body "\n try \{" append body \n { set reply [my Dispatch_Local $data] if {[dict size $reply]} {return $reply} } foreach {slot class} $mixinmap { set script [$class clay search plugin/ dispatch] if {[string length $script]} { append body \n "# SLOT $slot" append body \n $script } } append body \n { return [my Dispatch_Default $data]} append body \n "\} on error \{err errdat\} \{" append body \n { puts [list DISPATCH ERROR [dict get $errdat -errorinfo]] ; return {}} append body \n "\}" oo::objdefine [self] method dispatch data $body ### # rebuild the Headers_Process method ### set body "\n try \{" append body \n " upvar 1 \$varname query" append body \n { my Headers_Local query} foreach {slot class} $mixinmap { set script [$class clay search plugin/ headers] if {[string length $script]} { append body \n "# SLOT $slot" append body \n $script } } append body \n "\} on error \{err errdat\} \{" append body \n { puts [list HEADERS ERROR [dict get $errdat -errorinfo]] ; return {}} append body \n "\}" oo::objdefine [self] method Headers_Process varname $body ### # rebuild the Threads_Start method ### set body "\n try \{" foreach {slot class} $mixinmap { set script [$class clay search plugin/ thread] if {[string length $script]} { append body \n "# SLOT $slot" append body \n $script } } append body \n "\} on error \{err errdat\} \{" append body \n { puts [list THREAD START ERROR [dict get $errdat -errorinfo]] ; return {}} append body \n "\}" oo::objdefine [self] method Thread_start {} $body } # Return the actual port that httpd is listening on. method port_listening {} { my variable port_listening return $port_listening } # 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. method PrefixNormalize prefix { set prefix [string trimright $prefix /] set prefix [string trimright $prefix *] set prefix [string trimright $prefix /] return $prefix } method source {filename} { source $filename } # Open the socket listener. method start {} { # Build a namespace to contain replies namespace eval [namespace current]::reply {} my variable socklist port_listening if {[my clay get server/ configuration_file] ne {}} { source [my clay get server/ configuration_file] } set port [my clay get server/ port] if { $port in {auto {}} } { package require nettool set port [::nettool::allocate_port 8015] } set port_listening $port set myaddr [my clay get server/ myaddr] my debug [list [self] listening on $port $myaddr] if {$myaddr ni {all any * {}}} { foreach ip $myaddr { lappend socklist [socket -server [namespace code [list my connect]] -myaddr $ip $port] } } else { lappend socklist [socket -server [namespace code [list my connect]] $port] } ::cron::every [self] 120 [namespace code {my CheckTimeout}] my Thread_start } # Shut off the socket listener, and destroy any pending replies. method stop {} { my variable socklist if {[info exists socklist]} { foreach sock $socklist { catch {close $sock} } } set socklist {} ::cron::cancel [self] } Ensemble SubObject::db {} { return [namespace current]::Sqlite_db } Ensemble SubObject::default {} { return [namespace current]::$method } # Return a template for the string [arg page] method template page { my variable template if {[info exists template($page)]} { return $template($page) } set template($page) [my TemplateSearch $page] return $template($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. method TemplateSearch page { set doc_root [my clay get server/ doc_root] if {$doc_root ne {} && [file exists [file join $doc_root $page.tml]]} { return [::fileutil::cat [file join $doc_root $page.tml]] } if {$doc_root ne {} && [file exists [file join $doc_root $page.html]]} { return [::fileutil::cat [file join $doc_root $page.html]] } switch $page { redirect { return { [my html_header "$HTTP_STATUS"] The page you are looking for: <b>[my request get REQUEST_URI]</b> has moved. <p> If your browser does not automatically load the new location, it is <a href=\"$msg\">$msg</a> [my html_footer] } } internal_error { return { [my html_header "$HTTP_STATUS"] Error serving <b>[my request get REQUEST_URI]</b>: <p> The server encountered an internal server error: <pre>$msg</pre> <pre><code> $errorInfo </code></pre> [my html_footer] } } notfound { return { [my html_header "$HTTP_STATUS"] The page you are looking for: <b>[my request get REQUEST_URI]</b> does not exist. [my html_footer] } } } } ### # Built by the [cmd plugin] method. Called by the [cmd start] method. Intended # to allow plugins to spawn worker threads. ### method Thread_start {} {} ### # Generate a GUUID. Used to ensure every request has a unique ID. # The default implementation is: # [example { # return [::uuid::uuid generate] # }] ### method Uuid_Generate {} { return [::uuid::uuid generate] } ### # 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. ### method Validate_Connection {sock ip} { return 0 } } ### # Provide a backward compadible alias ### ::clay::define ::httpd::server::dispatch { superclass ::httpd::server } ### # END: server.tcl ### ### # START: dispatch.tcl ### ::clay::define ::httpd::content.redirect { method reset {} { ### # Inject the location into the HTTP headers ### my variable reply_body set reply_body {} my reply replace [my HttpHeaders_Default] my reply set Server [my <server> clay get server/ string] set msg [my clay get LOCATION] my reply set Location [my clay get LOCATION] set code [my clay get REDIRECT_CODE] if {$code eq {}} { set code 301 } my reply set Status [list $code [my http_code_string $code]] } method content {} { set template [my <server> template redirect] set msg [my clay get LOCATION] set HTTP_STATUS [my reply get Status] my puts [subst $msg] } } ::clay::define ::httpd::content.cache { method Dispatch {} { my variable chan try { my wait writable $chan chan configure $chan -translation {binary binary} chan puts -nonewline $chan [my clay get cache/ data] } on error {err info} { my <server> debug [dict get $info -errorinfo] } finally { my TransferComplete $chan } } } ::clay::define ::httpd::content.template { method content {} { if {[my request get HTTP_STATUS] ne {}} { my reply set Status [my request get HTTP_STATUS] } my puts [subst [my <server> template [my clay get template]]] } } ### # END: dispatch.tcl ### ### # START: file.tcl ### ### # Class to deliver Static content # When utilized, this class is fed a local filename # by the dispatcher ### ::clay::define ::httpd::content.file { method FileName {} { set uri [string trimleft [my request get REQUEST_URI] /] set path [my clay get path] set prefix [my clay get prefix] set fname [string range $uri [string length $prefix] end] if {$fname in "{} index.html index.md index"} { return $path } if {[file exists [file join $path $fname]]} { return [file join $path $fname] } if {[file exists [file join $path $fname.md]]} { return [file join $path $fname.md] } if {[file exists [file join $path $fname.html]]} { return [file join $path $fname.html] } if {[file exists [file join $path $fname.tml]]} { return [file join $path $fname.tml] } return {} } method DirectoryListing {local_file} { set uri [string trimleft [my request get REQUEST_URI] /] set path [my clay get path] set prefix [my clay get prefix] set fname [string range $uri [string length $prefix] end] my puts [my html_header "Listing of /$fname/"] my puts "Listing contents of /$fname/" my puts "<TABLE>" if {$prefix ni {/ {}}} { set updir [file dirname $prefix] if {$updir ne {}} { |
︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 | my puts [my html_footer] } method content {} { my variable reply_file set local_file [my FileName] if {$local_file eq {} || ![file exist $local_file]} { | | | 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 | my puts [my html_footer] } method content {} { my variable reply_file set local_file [my FileName] if {$local_file eq {} || ![file exist $local_file]} { my log httpNotFound [my request get REQUEST_URI] my error 404 {File Not Found} tailcall my DoOutput } if {[file isdirectory $local_file] || [file tail $local_file] in {index index.html index.tml index.md}} { ### # Produce an index page ### |
︙ | ︙ | |||
1228 1229 1230 1231 1232 1233 1234 | my reply set Content-Type {text/html; charset=UTF-8} set mdtxt [::fileutil::cat $local_file] my puts [::Markdown::convert $mdtxt] } .tml { my reply set Content-Type {text/html; charset=UTF-8} set tmltxt [::fileutil::cat $local_file] | | | < < < < < < < | 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 | my reply set Content-Type {text/html; charset=UTF-8} set mdtxt [::fileutil::cat $local_file] my puts [::Markdown::convert $mdtxt] } .tml { my reply set Content-Type {text/html; charset=UTF-8} set tmltxt [::fileutil::cat $local_file] set headers [my request dump] dict with headers {} my puts [subst $tmltxt] } default { ### # Assume we are returning a binary file ### my reply set Content-Type [::fileutil::magic::filetype $local_file] set reply_file $local_file } } } method Dispatch {} { my variable reply_body reply_file reply_chan chan try { my reset # Invoke the URL implementation. my content } on error {err errdat} { my error 500 $err [dict get $errdat -errorinfo] tailcall my DoOutput } |
︙ | ︙ | |||
1276 1277 1278 1279 1280 1281 1282 | ### set size [file size $reply_file] my reply set Content-Length $size append result [my reply output] \n chan puts -nonewline $chan $result set reply_chan [open $reply_file r] my log SendReply [list length $size] | < | < < < < < < < < < > | | | | 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 | ### set size [file size $reply_file] my reply set Content-Length $size append result [my reply output] \n chan puts -nonewline $chan $result set reply_chan [open $reply_file r] my log SendReply [list length $size] ### # Output the file contents. With no -size flag, channel will copy until EOF ### chan configure $reply_chan -translation {binary binary} -buffersize 4096 -buffering full -blocking 0 my ChannelCopy $reply_chan $chan -chunk 4096 } finally { my TransferComplete $reply_chan $chan } } } ### # END: file.tcl ### ### # START: proxy.tcl ### ::clay::define ::httpd::content.exec { variable exename [list tcl [info nameofexecutable] .tcl [info nameofexecutable]] method CgiExec {execname script arglist} { if { $::tcl_platform(platform) eq "windows"} { if {[file extension $script] eq ".exe"} { return [open "|[list $script] $arglist" r+] } else { |
︙ | ︙ | |||
1364 1365 1366 1367 1368 1369 1370 | return $result } } if {[dict exists exename $which]} { return [dict get $exename $which] } if {$which eq "tcl"} { | | | | | | | | | > | | | < > < < < < | < < | | | | | < < | | | < < < < < | | < < < < < < < < < > | | > > > | | | | | 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 | return $result } } if {[dict exists exename $which]} { return [dict get $exename $which] } if {$which eq "tcl"} { if {[my clay get tcl_exe] ne {}} { dict set exename $which [my clay get tcl_exe] } else { dict set exename $which [info nameofexecutable] } } else { if {[my clay get ${which}_exe] ne {}} { dict set exename $which [my clay get ${which}_exe] } elseif {"$::tcl_platform(platform)" == "windows"} { dict set exename $which $which.exe } else { dict set exename $which $which } } set result [dict get $exename $which] if {$ext ne {}} { dict set exename $ext $result } return $result } } ### # Return data from an proxy process ### ::clay::define ::httpd::content.proxy { superclass ::httpd::content.exec method proxy_channel {} { ### # This method returns a channel to the # proxied socket/stdout/etc ### error unimplemented } method proxy_path {} { set uri [string trimleft [my request get REQUEST_URI] /] set prefix [my clay get prefix] return /[string range $uri [string length $prefix] end] } method ProxyRequest {chana chanb} { chan event $chanb writable {} my log ProxyRequest {} chan puts $chanb "[my request get REQUEST_METHOD] [my proxy_path]" set mimetxt [my clay get mimetxt] chan puts $chanb [my clay get mimetxt] set length [my request get CONTENT_LENGTH] if {$length} { chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 ### # Send any POST/PUT/etc content ### my ChannelCopy $chana $chanb -size $length } else { chan flush $chanb } chan event $chanb readable [info coroutine] yield } method ProxyReply {chana chanb args} { my log ProxyReply [list args $args] chan event $chana readable {} set readCount [::coroutine::util::gets_safety $chana 4096 reply_status] set replyhead [my HttpHeaders $chana] set replydat [my MimeParse $replyhead] ### # Read the first incoming line as the HTTP reply status # Return the rest of the headers verbatim ### set replybuffer "$reply_status\n" append replybuffer $replyhead chan configure $chanb -translation {auto crlf} -blocking 0 -buffering full -buffersize 4096 chan puts $chanb $replybuffer ### # Output the body. With no -size flag, channel will copy until EOF ### chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 my ChannelCopy $chana $chanb -chunk 4096 } method Dispatch {} { my variable sock chan if {[catch {my proxy_channel} sock errdat]} { my error 504 {Service Temporarily Unavailable} [dict get $errdat -errorinfo] tailcall my DoOutput } if {$sock eq {}} { my error 404 {Not Found} tailcall my DoOutput } my log HttpAccess {} chan event $sock writable [info coroutine] yield try { my ProxyRequest $chan $sock my ProxyReply $sock $chan } finally { my TransferComplete $chan $sock } } } ### # END: proxy.tcl ### ### # START: cgi.tcl ### ::clay::define ::httpd::content.cgi { superclass ::httpd::content.proxy method FileName {} { set uri [string trimleft [my request get REQUEST_URI] /] set path [my clay get path] set prefix [my clay get prefix] set fname [string range $uri [string length $prefix] end] if {[file exists [file join $path $fname]]} { return [file join $path $fname] } if {[file exists [file join $path $fname.fossil]]} { return [file join $path $fname.fossil] |
︙ | ︙ | |||
1525 1526 1527 1528 1529 1530 1531 | method proxy_channel {} { ### # When delivering static content, allow web caches to save ### set local_file [my FileName] if {$local_file eq {} || ![file exist $local_file]} { | | | 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 | method proxy_channel {} { ### # When delivering static content, allow web caches to save ### set local_file [my FileName] if {$local_file eq {} || ![file exist $local_file]} { my log httpNotFound [my request get REQUEST_URI] my error 404 {Not Found} tailcall my DoOutput } if {[file isdirectory $local_file]} { ### # Produce an index page... or error ### |
︙ | ︙ | |||
1549 1550 1551 1552 1553 1554 1555 | } foreach item $verbatim { set ::env($item) {} } foreach item [array names ::env HTTP_*] { set ::env($item) {} } | | | < | < < < < < < < < | 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 | } foreach item $verbatim { set ::env($item) {} } foreach item [array names ::env HTTP_*] { set ::env($item) {} } set ::env(SCRIPT_NAME) [my request get REQUEST_PATH] set ::env(SERVER_PROTOCOL) HTTP/1.0 set ::env(HOME) $::env(DOCUMENT_ROOT) foreach {f v} [my request dump] { set ::env($f) $v } set arglist $::env(QUERY_STRING) set pwd [pwd] cd [file dirname $local_file] set script_file $local_file if {[file extension $local_file] in {.fossil .fos}} { if {![file exists $local_file.cgi]} { set fout [open $local_file.cgi w] chan puts $fout "#!/usr/bin/fossil" chan puts $fout "repository: $local_file" close $fout |
︙ | ︙ | |||
1589 1590 1591 1592 1593 1594 1595 | cd $pwd return $pipe } method ProxyRequest {chana chanb} { chan event $chanb writable {} my log ProxyRequest {} | | | < > < | 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 | cd $pwd return $pipe } method ProxyRequest {chana chanb} { chan event $chanb writable {} my log ProxyRequest {} set length [my request get CONTENT_LENGTH] if {$length} { chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 ### # Send any POST/PUT/etc content ### my ChannelCopy $chana $chanb -size $length } else { chan flush $chanb } chan event $chanb readable [info coroutine] yield } method ProxyReply {chana chanb args} { my log ProxyReply [list args $args] chan event $chana readable {} set replyhead [my HttpHeaders $chana] |
︙ | ︙ | |||
1625 1626 1627 1628 1629 1630 1631 | # a standard service reply line from a web server, but # otherwise spit out the rest of the headers verbatim ### set replybuffer "HTTP/1.0 [dict get $replydat Status]\n" append replybuffer $replyhead chan configure $chanb -translation {auto crlf} -blocking 0 -buffering full -buffersize 4096 chan puts $chanb $replybuffer | < < | | | | | < < | < > > > > > > > | > | | | > | < > < < < < < < < | | | | | < < < < < < | < < < < < | | | | | > > | > | > < < | < < | < | | | | | | | > > | | | < | > > > | | < < < < < < < < < < < < < < < < < < < < | < < > | < < < | < | | | | | | | < > | | | | | | | | | > > > > | | | > | | | | | | | < | | < < < < < < < | | < < < > | | | < < < < < < < < < < < < < | > > > > > > | > > > > > > > > > > | | | | 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 | # a standard service reply line from a web server, but # otherwise spit out the rest of the headers verbatim ### set replybuffer "HTTP/1.0 [dict get $replydat Status]\n" append replybuffer $replyhead chan configure $chanb -translation {auto crlf} -blocking 0 -buffering full -buffersize 4096 chan puts $chanb $replybuffer ### # Output the body. With no -size flag, channel will copy until EOF ### chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 my ChannelCopy $chana $chanb -chunk 4096 } ### # For most CGI applications a directory list is vorboten ### method DirectoryListing {local_file} { my error 403 {Not Allowed} tailcall my DoOutput } } ### # END: cgi.tcl ### ### # START: scgi.tcl ### ### # Return data from an SCGI process ### ::clay::define ::httpd::protocol.scgi { method EncodeStatus {status} { return "Status: $status" } } ::clay::define ::httpd::content.scgi { superclass ::httpd::content.proxy method scgi_info {} { ### # This method should check if a process is launched # or launch it if needed, and return a list of # HOST PORT SCRIPT_NAME ### # return {localhost 8016 /some/path} error unimplemented } method proxy_channel {} { set sockinfo [my scgi_info] if {$sockinfo eq {}} { my error 404 {Not Found} tailcall my DoOutput } lassign $sockinfo scgihost scgiport scgiscript my clay set SCRIPT_NAME $scgiscript if {![string is integer $scgiport]} { my error 404 {Not Found} tailcall my DoOutput } return [::socket $scgihost $scgiport] } method ProxyRequest {chana chanb} { chan event $chanb writable {} my log ProxyRequest {} chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 set info [dict create CONTENT_LENGTH 0 SCGI 1.0 SCRIPT_NAME [my clay get SCRIPT_NAME]] foreach {f v} [my request dump] { dict set info $f $v } set length [dict get $info CONTENT_LENGTH] set block {} foreach {f v} $info { append block [string toupper $f] \x00 $v \x00 } chan puts -nonewline $chanb "[string length $block]:$block," # Light off another coroutine #set cmd [list coroutine [my CoroName] {*}[namespace code [list my ProxyReply $chanb $chana]]] if {$length} { chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 ### # Send any POST/PUT/etc content ### my ChannelCopy $chana $chanb -size $length #chan copy $chana $chanb -size $length -command [info coroutine] } else { chan flush $chanb } chan event $chanb readable [info coroutine] yield } method ProxyReply {chana chanb args} { my log ProxyReply [list args $args] chan event $chana readable {} set replyhead [my HttpHeaders $chana] set replydat [my MimeParse $replyhead] ### # Convert the Status: header from the CGI process to # a standard service reply line from a web server, but # otherwise spit out the rest of the headers verbatim ### set replybuffer "HTTP/1.0 [dict get $replydat Status]\n" append replybuffer $replyhead chan configure $chanb -translation {auto crlf} -blocking 0 -buffering full -buffersize 4096 chan puts $chanb $replybuffer ### # Output the body. With no -size flag, channel will copy until EOF ### chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096 chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096 my ChannelCopy $chana $chanb -chunk 4096 } } ### # Act as an SCGI Server ### ::clay::define ::httpd::server.scgi { superclass ::httpd::server clay set socket/ buffersize 32768 clay set socket/ blocking 0 clay set socket/ translation {binary binary} method debug args { puts $args } method Connect {uuid sock ip} { yield [info coroutine] chan event $sock readable {} chan configure $sock \ -blocking 1 \ -translation {binary binary} \ -buffersize 4096 \ -buffering none my counter url_hit try { # Read the SCGI request on byte at a time until we reach a ":" dict set query http HTTP_HOST {} dict set query http CONTENT_LENGTH 0 dict set query http REQUEST_URI / dict set query http REMOTE_ADDR $ip set size {} while 1 { set char [::coroutine::util::read $sock 1] if {[chan eof $sock]} { catch {close $sock} return } if {$char eq ":"} break append size $char } # With length in hand, read the netstring encoded headers set inbuffer [::coroutine::util::read $sock [expr {$size+1}]] chan configure $sock -blocking 0 -buffersize 4096 -buffering full foreach {f v} [lrange [split [string range $inbuffer 0 end-1] \0] 0 end-1] { dict set query http $f $v } if {![dict exists $query http REQUEST_PATH]} { set uri [dict get $query http REQUEST_URI] set uriinfo [::uri::split $uri] dict set query http REQUEST_PATH [dict get $uriinfo path] } set reply [my dispatch $query] } on error {err errdat} { my debug [list uri: [dict getnull $query http REQUEST_URI] ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] my log BadRequest $uuid [list ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] catch {chan puts $sock "HTTP/1.0 400 Bad Request (The data is invalid)"} catch {chan event readable $sock {}} catch {chan event writeable $sock {}} catch {chan close $sock} return } if {[dict size $reply]==0} { my log BadLocation $uuid $query dict set query http HTTP_STATUS 404 dict set query template notfound dict set query mixin reply ::httpd::content.template } try { set pageobj [::httpd::reply create ::httpd::object::$uuid [self]] dict set reply mixin protocol ::httpd::protocol.scgi $pageobj dispatch $sock $reply } on error {err errdat} { my debug [list ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] my log BadRequest $uuid [list ip: $ip error: $err errorinfo: [dict get $errdat -errorinfo]] catch {$pageobj destroy} catch {chan event readable $sock {}} catch {chan event writeable $sock {}} catch {chan close $sock} return } } } ### # END: scgi.tcl ### ### # START: websocket.tcl ### ### # Upgrade a connection to a websocket ### ::clay::define ::httpd::content.websocket { } ### # END: websocket.tcl ### ### # START: plugin.tcl ### ### # httpd plugin template ### ::clay::define ::httpd::plugin { ### # Any options will be saved to the local config file # to allow threads to pull up a snapshot of the object' configuration ### ### # Define a code snippet to run on plugin load ### clay set plugin/ load {} ### # Define a code snippet to run within the object's Headers_Process method ### clay set plugin/ headers {} ### # Define a code snippet to run within the object's dispatch method ### clay set plugin/ dispatch {} ### # Define a code snippet to run within the object's writes a local config file ### clay set plugin/ local_config {} ### # When after all the plugins are loaded # allow specially configured ones to light off a thread ### clay set plugin/ thread {} } ### # A rudimentary plugin that dispatches URLs from a dict # data structure ### ::clay::define ::httpd::plugin.dict_dispatch { clay set plugin/ dispatch { set reply [my Dispatch_Dict $data] if {[dict size $reply]} { return $reply } } ### # Implementation of the dispatcher ### method Dispatch_Dict {data} { my variable url_patterns set vhost [lindex [split [dict get $data http HTTP_HOST] :] 0] set uri [dict get $data http REQUEST_PATH] foreach {host hostpat} $url_patterns { if {![string match $host $vhost]} continue foreach {pattern info} $hostpat { if {![string match $pattern $uri]} continue set buffer $data foreach {f v} $info { dict set buffer $f $v } return $buffer } } return {} } ### # Ensemble uri::add {vhosts patterns info} { my variable url_patterns foreach vhost $vhosts { foreach pattern $patterns { set data $info if {![dict exists $data prefix]} { dict set data prefix [my PrefixNormalize $pattern] } dict set url_patterns $vhost [string trimleft $pattern /] $data } } } Ensemble uri::direct {vhosts patterns info body} { my variable url_patterns url_stream set cbody {} if {[dict exists $info superclass]} { append cbody \n "superclass {*}[dict get $info superclass]" dict unset info superclass } append cbody \n [list method content {} $body] set class [namespace current]::${vhosts}/${patterns} set class [string map {* %} $class] ::clay::define $class $cbody dict set info mixin content $class my uri add $vhosts $patterns $info } } ::clay::define ::httpd::reply.memchan { superclass ::httpd::reply method output {} { my variable reply_body return $reply_body } method DoOutput {} {} method close {} { # Neuter the channel closing mechanism we need the channel to stay alive # until the reader sucks out the info } } ::clay::define ::httpd::plugin.local_memchan { clay set plugin/ load { package require tcl::chan::events package require tcl::chan::memchan } method local_memchan {command args} { my variable sock_to_coro switch $command { |
︙ | ︙ | |||
2042 2043 2044 2045 2046 2047 2048 | chan configure $sock \ -blocking 0 \ -translation {auto crlf} \ -buffering line set ip 127.0.0.1 dict set query UUID $uuid | > | | | | | | | | | | | | | | | | < < < | | | | 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 | chan configure $sock \ -blocking 0 \ -translation {auto crlf} \ -buffering line set ip 127.0.0.1 dict set query UUID $uuid dict set query http UUID $uuid dict set query http HTTP_HOST localhost dict set query http REMOTE_ADDR 127.0.0.1 dict set query http REMOTE_HOST localhost dict set query http LOCALHOST 1 my counter url_hit dict set query http REQUEST_METHOD [lindex $args 0] set uriinfo [::uri::split [lindex $args 1]] dict set query http REQUEST_URI [lindex $args 1] dict set query http REQUEST_PATH [dict get $uriinfo path] dict set query http REQUEST_VERSION [lindex [split [lindex $args end] /] end] dict set query http DOCUMENT_ROOT [my clay get server/ doc_root] dict set query http QUERY_STRING [dict get $uriinfo query] dict set query http REQUEST_RAW $args dict set query http SERVER_PORT [my port_listening] my Headers_Process query set reply [my dispatch $query] if {[llength $reply]==0} { my log BadLocation $uuid $query my log BadLocation $uuid $query dict set query http HTTP_STATUS 404 dict set query template notfound dict set query mixin reply ::httpd::content.template } set class ::httpd::reply.memchan set pageobj [$class create ::httpd::object::$uuid [self]] if {[dict exists $reply mixin]} { set mixinmap [dict get $reply mixin] } else { set mixinmap {} } foreach item [dict keys $reply MIXIN_*] { set slot [string range $reply 6 end] dict set mixinmap [string tolower $slot] [dict get $reply $item] } $pageobj clay mixinmap {*}$mixinmap if {[dict exists $reply delegate]} { $pageobj clay delegate {*}[dict get $reply delegate] } $pageobj dispatch $sock $reply set output [$pageobj output] catch {$pageobj destroy} return $output } } |
︙ | ︙ |
Changes to modules/httpd/httpd.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | testsNeedTcltest 2 testsNeed TclOO 1 support { use cmdline/cmdline.tcl cmdline use fileutil/fileutil.tcl fileutil use sha1/sha1.tcl sha1 use uri/uri.tcl uri use ncgi/ncgi.tcl ncgi use dns/ip.tcl ip use nettool/nettool.tcl nettool use coroutine/coroutine.tcl coroutine use dicttool/dicttool.tcl dicttool use cron/cron.tcl cron | > < < | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | testsNeedTcltest 2 testsNeed TclOO 1 support { use cmdline/cmdline.tcl cmdline use fileutil/fileutil.tcl fileutil use uuid/uuid.tcl uuid use sha1/sha1.tcl sha1 use uri/uri.tcl uri use ncgi/ncgi.tcl ncgi use dns/ip.tcl ip use nettool/nettool.tcl nettool use coroutine/coroutine.tcl coroutine use dicttool/dicttool.tcl dicttool use cron/cron.tcl cron use clay/clay.tcl clay use virtchannel_core/core.tcl tcl::chan::core use virtchannel_core/events.tcl tcl::chan::events use virtchannel_base/memchan.tcl tcl::chan::memchan } testing { useLocal httpd.tcl httpd } # Set to true for debugging and traces set ::DEBUG 0 set ::clay::debug $::DEBUG proc DEBUG args { if {$::DEBUG} { uplevel 1 $args } } |
︙ | ︙ | |||
115 116 117 118 119 120 121 | chan event $sock readable {} set [namespace current]::reply($sock) $buffer($sock) unset buffer($sock) } } | | < | > > > > | | | | | | | | | | | | | | | | | 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 | chan event $sock readable {} set [namespace current]::reply($sock) $buffer($sock) unset buffer($sock) } } clay::define ::httpd::server { method log args {} method TemplateSearch page { set doc_root [my clay get server/ doc_root] if {$doc_root ne {} && [file exists [file join $doc_root $page.tml]]} { return [::fileutil::cat [file join $doc_root $page.tml]] } if {$doc_root ne {} && [file exists [file join $doc_root $page.html]]} { return [::fileutil::cat [file join $doc_root $page.html]] } switch $page { redirect { return {300 Redirect} } notfound { return {404 Not Found} } internal_error { return {500 Server Internal Error} } } } ::DEBUG method debug args { puts stderr $args } ::DEBUG method log args { puts stdout $args } } ### # Modify the reply class to return plain text ### clay::define ::httpd::reply { method HttpHeaders_Default {} { return {Status {200 OK} Content-Type {text/plain} Connection close} } method reset {} { my variable reply_body my reply replace [my HttpHeaders_Default] set reply_body {} } method error {code {msg {}} {errorInfo {}}} { my clay set HTTP_ERROR $code my reset set errorstring [my http_code_string $code] set qheaders [my clay dump] dict with qheaders {} my reply replace {} my reply set Status "$code $errorstring" my reply set Content-Type text/plain my puts "$code $errorstring" } } clay::define ::test::content.echo { method content {} { my variable reply_body set reply_body [my PostData [my request get CONTENT_LENGTH]] #puts [list REPLY BODY WAS $reply_body] } } clay::define ::test::content.file { superclass ::httpd::content.file method content {} { my reset set doc_root [my request get DOCUMENT_ROOT] my variable reply_file set reply_file [file join $doc_root pkgIndex.tcl] } } clay::define ::test::content.time { method content {} { my variable reply_body set reply_body [clock seconds] } } clay::define ::test::content.error { method content {} { error {The programmer asked me to die this way} } } clay::define ::test::content.cgi { superclass ::httpd::content.cgi } clay::define ::httpd::test::reply { superclass ::httpd::reply ::test::content.echo } ### # Build the server ### set DIR [file dirname [file normalize [info script]]] set ::DEMOROOT $DIR ::httpd::server create TESTAPP port 10001 TESTAPP plugin dict_dispatch TESTAPP uri add * / [list mixin {reply ::test::content.echo}] TESTAPP uri add * /echo [list mixin {reply ::test::content.echo}] TESTAPP uri add * /file [list mixin {reply ::test::content.file} doc_root $::DEMOROOT] TESTAPP uri add * /time [list mixin {reply ::test::content.time}] TESTAPP uri add * /error [list mixin {replyy ::test::content.error}] # Catch all #TESTAPP uri add * * [list mixin {reply httpd::content.echo}] ::DEBUG puts httpd-client-0001 test httpd-client-0001 {Do an echo request} { set reply [::httpd::test::send 10001 {POST /echo HTTP/1.0} {} {THIS IS MY CODE}] ::httpd::test::compare $reply {HTTP/1.0 200 OK Content-Type: text/plain |
︙ | ︙ | |||
306 307 308 309 310 311 312 313 314 315 316 | ::DEBUG puts httpd-client-0006 test httpd-client-0006 {Return a file} { set reply [::httpd::test::send 10001 {GET /file HTTP/1.0} {} {}] ::httpd::test::compare $reply $checkreply } {} # ------------------------------------------------------------------------- # Test proxies | > > > > > > > > > > > > | < | | | | | | | | 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 | ::DEBUG puts httpd-client-0006 test httpd-client-0006 {Return a file} { set reply [::httpd::test::send 10001 {GET /file HTTP/1.0} {} {}] ::httpd::test::compare $reply $checkreply } {} ::DEBUG puts httpd-client-0007 test httpd-client-0007 {URL Generates Not Found} { set reply [::httpd::test::send 10001 {POST /doesnotexist HTTP/1.0} {} {THIS ONE ALONE IS MINE}] ::httpd::test::compare $reply {HTTP/1.0 404 Not Found Content-Type: text/plain Connection: close Content-Length: * 404 Not Found} } {} # ------------------------------------------------------------------------- # Test proxies clay::define ::test::content.proxy { superclass ::httpd::content.proxy method proxy_channel {} { return [::socket localhost [my clay get proxy_port]] } } ::httpd::server create TESTPROXY port 10002 TESTAPP uri add * /proxy* [list mixin {reply ::test::content.proxy} proxy_port [TESTPROXY port_listening]] TESTPROXY plugin dict_dispatch TESTPROXY uri add * / [list mixin {reply ::test::content.echo}] TESTPROXY uri add * /echo [list mixin {reply ::test::content.echo}] TESTPROXY uri add * /file [list mixin {reply ::test::content.file} doc_root $::DEMOROOT] TESTPROXY uri add * /time [list mixin {reply ::test::content.time}] TESTPROXY uri add * /error [list mixin {reply ::test::content.error}] ::DEBUG puts httpd-proxy-0001 test httpd-proxy-0001 {Do an echo request} { set reply [::httpd::test::send 10001 {POST /proxy/echo HTTP/1.0} {} {THIS IS MY CODE}] ::httpd::test::compare $reply {HTTP/1.0 200 OK Content-Type: text/plain |
︙ | ︙ | |||
405 406 407 408 409 410 411 | ::DEBUG puts httpd-proxy-0006 test httpd-proxy-0006 {Return a file} { set reply [::httpd::test::send 10001 {GET /proxy/file HTTP/1.0} {} {}] ::httpd::test::compare $reply $checkreply } {} | < < | | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | ::DEBUG puts httpd-proxy-0006 test httpd-proxy-0006 {Return a file} { set reply [::httpd::test::send 10001 {GET /proxy/file HTTP/1.0} {} {}] ::httpd::test::compare $reply $checkreply } {} # ------------------------------------------------------------------------- # cgi TESTAPP plugin local_memchan TESTAPP uri add * /cgi-bin* [list mixin {reply ::test::content.cgi} path $::DEMOROOT] set fout [open [file join $DIR test.tcl] w] puts $fout {#!/usr/bin/tclsh puts stdout "Status: 200 OK" if {$::env(CONTENT_LENGTH) > 0} { puts stdout "Content-Type: $::env(CONTENT_TYPE)" |
︙ | ︙ | |||
543 544 545 546 547 548 549 | namespace eval ::scgi { variable server_block {SCGI 1.0 SERVER_SOFTWARE {TclScgiServer/0.1}} } ### # Build the reply class ### | | | | | > | | | | | > | 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 | namespace eval ::scgi { variable server_block {SCGI 1.0 SERVER_SOFTWARE {TclScgiServer/0.1}} } ### # Build the reply class ### ::clay::define ::scgi::test::reply { superclass ::httpd::reply method reset {} { my variable reply_body my reply replace [my HttpHeaders_Default] set reply_body {} } } ### # Build the server ### ::clay::define scgi::test::app { superclass ::httpd::server.scgi clay set reply_class ::scgi::test::reply } puts [list ::test::content.file [info commands ::test::content.file]] scgi::test::app create TESTSCGI port 10003 TESTSCGI plugin dict_dispatch TESTSCGI uri add * / [list mixin {reply ::test::content.echo}] TESTSCGI uri add * /echo [list mixin {reply ::test::content.echo}] TESTSCGI uri add * /file [list mixin {reply ::test::content.file} doc_root $::DEMOROOT] TESTSCGI uri add * /time [list mixin {reply ::test::content.time}] TESTSCGI uri add * /error [list mixin {reply ::test::content.error}] ::DEBUG puts scgi-client-0001 test scgi-client-0001 {Do an echo request} { set reply [::scgi::test::send 10003 {REQUEST_METHOD POST REQUEST_URI /echo} {THIS IS MY CODE}] set checkreply {Status: 200 OK Content-Type: text/plain Connection: close Content-Length: * THIS IS MY CODE} ::httpd::test::compare $reply $checkreply } {} ::DEBUG puts scgi-client-0002 test scgi-client-0002 {Do another echo request} { set reply [::scgi::test::send 10003 {REQUEST_METHOD POST REQUEST_URI /echo} {THOUGH THERE ARE MANY LIKE IT}] set checkreply {Status: 200 OK Content-Type: text/plain Connection: close |
︙ | ︙ | |||
654 655 656 657 658 659 660 | Content-Length: [string length $checkfile] $checkfile" ::httpd::test::compare $reply $checkreply } {} ::DEBUG puts all-tests-finished | | | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 | Content-Length: [string length $checkfile] $checkfile" ::httpd::test::compare $reply $checkreply } {} ::DEBUG puts all-tests-finished file delete [file join $DIR test.tcl] # ------------------------------------------------------------------------- testsuiteCleanup # Local variables: # mode: tcl # indent-tabs-mode: nil # End: |
Changes to modules/httpd/pkgIndex.tcl.
1 2 | if {![package vsatisfies [package provide Tcl] 8.6]} {return} | | | 1 2 3 4 | if {![package vsatisfies [package provide Tcl] 8.6]} {return} package ifneeded httpd 4.3 [list source [file join $dir httpd.tcl]] |
Changes to modules/ldap/ldap.man.
1 | [comment {-*- tcl -*- doctools manpage}] | | | 1 2 3 4 5 6 7 8 9 | [comment {-*- tcl -*- doctools manpage}] [vset VERSION 1.10] [manpage_begin ldap n [vset VERSION]] [keywords {directory access}] [keywords internet] [keywords ldap] [keywords {ldap client}] [keywords protocol] [keywords {rfc 2251}] |
︙ | ︙ | |||
26 27 28 29 30 31 32 | RFC 4511 ([uri http://www.rfc-editor.org/rfc/rfc4511.txt]). It works by opening the standard (or secure) LDAP socket on the server, and then providing a Tcl API to access the LDAP protocol commands. All server errors are returned as Tcl errors (thrown) which must be caught with the Tcl [cmd catch] command. | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > < < < < | > > > > > > > > > > > > > > > | 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 | RFC 4511 ([uri http://www.rfc-editor.org/rfc/rfc4511.txt]). It works by opening the standard (or secure) LDAP socket on the server, and then providing a Tcl API to access the LDAP protocol commands. All server errors are returned as Tcl errors (thrown) which must be caught with the Tcl [cmd catch] command. [section {TLS Security Considerations}] [para] This package uses the [package TLS] package to handle the security for [const LDAPS] connections. [para] Policy decisions like the set of protocols to support and what ciphers to use are not the responsibility of [package TLS], nor of this package itself however. Such decisions are the responsibility of whichever application is using the package, and are likely influenced by the set of servers the application will talk to as well. [para] For example, in light of the recent [uri http://googleonlinesecurity.blogspot.co.uk/2014/10/this-poodle-bites-exploiting-ssl-30.html \ {POODLE attack}] discovered by Google many servers will disable support for the SSLv3 protocol. To handle this change the applications using [package TLS] must be patched, and not this package, nor [package TLS] itself. Such a patch may be as simple as generally activating [const tls1] support, as shown in the example below. [example { ldap::tlsoptions -tls1 1 -ssl2 0 -ssl3 0 ;# forcibly activate support for the TLS1 protocol ... your own application code ... }] [section COMMANDS] [list_begin definitions] [call [cmd ::ldap::connect] [arg host] [opt [arg port]]] Opens a LDAPv3 connection to the specified [arg host], at the given [arg port], and returns a token for the connection. This token is the [arg handle] argument for all other commands. If no [arg port] is specified it will default to [const 389]. [para] The command blocks until the connection has been established, or establishment definitely failed. [call [cmd ::ldap::tlsoptions] [cmd reset]] This command resets TLS options to default values. It returns the set of options. Using this command is incompatible with the obsolete form of [cmd ::ldap::secure_connect] and [cmd ::ldap_starttls]. [call [cmd ::ldap::tlsoptions] [opt "[arg opt1] [arg val1]"] [opt "[arg opt2] [arg val2]"] ...] This commands adds one or more options to some value, and may be used more than one time in order to add options in several steps. A complete description of options may be found in the [package tls] package documentation. Valid options and values are: [list_begin options] [opt_def {-cadir} directory ] Provide the directory containing the CA certificates. No default. [opt_def {-cafile} file] Provide the CA file. No default. [opt_def {-cipher} string] Provide the cipher suites to use. No default. [opt_def {-dhparams} file] Provide a Diffie-Hellman parameters file. No default. [opt_def {-request} boolean] Request a certificate from peer during SSL handshake. Default: true. [opt_def {-require} boolean] Require a valid certificate from peer during SSL handshake. If this is set to true then -request must also be set to true. Default: false [opt_def {-servername} host] Only available if the OpenSSL library the TLS package is linked against supports the TLS hostname extension for 'Server Name Indication' (SNI). Use to name the logical host we are talking to and expecting a certificate for. No default. [opt_def {-ssl2} bool] Enable use of SSL v2. Default: false [opt_def {-ssl3} bool] Enable use of SSL v3. Default: false [opt_def {-tls1} bool] Enable use of TLS v1 Default: true [opt_def {-tls1.1} bool] Enable use of TLS v1.1 Default: true [opt_def {-tls1.2} bool] Enable use of TLS v1.2 Default: true [list_end] [para] This command returns the current set of TLS options and values. In particular, one may use this command without any arguments to get the current set of options. [para] Using this command is incompatible with the obsolete form of [cmd ::ldap::secure_connect] and [cmd ::ldap_starttls] (see below). [call [cmd ::ldap::secure_connect] [arg host] [opt [arg port]]] Like [cmd ::ldap::connect], except that the created connection is secured by SSL. The port defaults to [const 636]. This command depends on the availability of the package [package TLS], which is a SSL binding for Tcl. If [package TLS] is not available, then this command will fail. [para] TLS options are specified with [cmd ::ldap::tlsoptions]. [para] The command blocks until the connection has been established, or establishment definitely failed. [call [cmd ::ldap::secure_connect] [arg host] [opt [arg port]] [opt [arg verify_cert]] [opt [arg sni_servername]]] Note: this form of the command is deprecated, since TLS options had to be specified with a combination of parameters to this command ([arg verify_cert] and [arg sni_servername]) and arguments to [cmd ::tls::init] (from package [package tls]) for example to setup defaults for trusted certificates. Prefer the above form (without the [arg verify_cert] and [arg sni_servername] parameters) and set TLS options with [cmd ::ldap::tlsoptions]. [para] If [arg verify_cert] is set to 1, the default, this checks the server certificate against the known hosts. If [arg sni_servername] is set, the given hostname is used as the hostname for Server Name Indication in the TLS handshake. [para] Use [cmd ::tls::init] to setup defaults for trusted certificates. [para] TLS supports different protocol levels. In common use are the versions 1.0, 1.1 and 1.2. By default all those versions are offered. If you need to modify the acceptable protocols, you can change the ::ldap::tlsProtocols list (deprecated). [call [cmd ::ldap::disconnect] [arg handle]] Closes the ldap connection refered to by the token [arg handle]. Returns the empty string as its result. [call [cmd ::ldap::starttls] [arg handle]] Start TLS negotiation on the connection denoted by [arg handle], with TLS parameters set with [cmd ::ldap::tlsoptions]. [call [cmd ::ldap::starttls] [arg handle] [opt [arg cafile]] [opt [arg certfile]] [opt [arg keyfile]] [opt [arg verify_cert]] [opt [arg sni_servername]]] Note: this form of the command is deprecated, since TLS options had to be specified with a combination of parameters to this command ([arg cafile], [arg certfile], [arg keyfile], [arg verify_cert] and [arg sni_servername]) and arguments to [cmd ::tls::init] (from package [package tls]). Prefer the above form (without specific TLS arguments) and set TLS options with [cmd ::ldap::tlsoptions]. [para] Start TLS negotiation on the connection denoted by [arg handle]. You need to set at least the [arg cafile] argument to a file with trusted certificates, if [arg verify_cert] is 1, which is the default. The [arg sni_servername] can be used to signal a different hostname during the TLS handshake. The announced protocols are determined in the same way as [cmd ::ldap::secure_connect]. |
︙ | ︙ | |||
409 410 411 412 413 414 415 416 417 418 419 420 421 422 | This command returns all currently existing ldap connection handles. [call [cmd ::ldap::info] [cmd tls] [arg handle] ] This command returns 1 if the ldap connection [arg handle] used TLS/SSL for connection via [cmd ldap::secure_connect] or completed [cmd ldap::starttls], 0 otherwise. [call [cmd ::ldap::info] [cmd saslmechanisms] [arg handle]] Return the supported SASL mechanisms advertised by the server. Only valid in a bound state (anonymous or other). [call [cmd ::ldap::info] [cmd control] [arg handle] ] | > > > > > > > | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | This command returns all currently existing ldap connection handles. [call [cmd ::ldap::info] [cmd tls] [arg handle] ] This command returns 1 if the ldap connection [arg handle] used TLS/SSL for connection via [cmd ldap::secure_connect] or completed [cmd ldap::starttls], 0 otherwise. [call [cmd ::ldap::info] [cmd tlsstatus] [arg handle] ] This command returns the current security status of an TLS secured channel. The result is a list of key-value pairs describing the connected peer (see the [package TLS] package documentation for the returned values). If the connection is not secured with TLS, an empty list is returned. [call [cmd ::ldap::info] [cmd saslmechanisms] [arg handle]] Return the supported SASL mechanisms advertised by the server. Only valid in a bound state (anonymous or other). [call [cmd ::ldap::info] [cmd control] [arg handle] ] |
︙ | ︙ | |||
499 500 501 502 503 504 505 | ldap::delete $handle $dn ldap::unbind $handle ldap::disconnect $handle }] [para] | | | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | ldap::delete $handle $dn ldap::unbind $handle ldap::disconnect $handle }] [para] And another example, a simple query, and processing the results. [para] [example { package require ldap set handle [ldap::connect ldap.acme.com 389] ldap::bind $handle |
︙ | ︙ |
Changes to modules/ldap/ldap.tcl.
︙ | ︙ | |||
40 41 42 43 44 45 46 | # written by Jochen Loewer # 3 June, 1999 # #----------------------------------------------------------------------------- package require Tcl 8.4 package require asn 0.7 | | > > | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | # written by Jochen Loewer # 3 June, 1999 # #----------------------------------------------------------------------------- package require Tcl 8.4 package require asn 0.7 package provide ldap 1.10 namespace eval ldap { namespace export connect secure_connect \ starttls \ tlsoptions \ disconnect \ bind unbind \ bindSASL \ search \ searchInit \ searchNext \ searchEnd \ |
︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 66 notAllowedOnNonLeaf 67 notAllowedOnRDN 68 entryAlreadyExists 69 objectClassModsProhibited 80 other } } #----------------------------------------------------------------------------- # Lookup an numerical ldap result code and return a string version # #----------------------------------------------------------------------------- | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 66 notAllowedOnNonLeaf 67 notAllowedOnRDN 68 entryAlreadyExists 69 objectClassModsProhibited 80 other } # TLS options for secure_connect and starttls # (see tcltls documentation, function tls::import) variable validTLSOptions set validTLSOptions { -cadir -cafile -certfile -cipher -command -dhparams -keyfile -model -password -request -require -server -servername -ssl2 -ssl3 -tls1 -tls1.1 -tls1.2 } # Default TLS options for secure_connect and starttls variable defaultTLSOptions array set defaultTLSOptions { -request 1 -require 1 -ssl2 no -ssl3 no -tls1 yes -tls1.1 yes -tls1.2 yes } variable curTLSOptions array set curTLSOptions [array get defaultTLSOptions] # are we using the old interface (TLSMode = "compatible") or the # new one (TLSMode = "integrated") variable TLSMode set TLSMode "compatible" } #----------------------------------------------------------------------------- # Lookup an numerical ldap result code and return a string version # #----------------------------------------------------------------------------- |
︙ | ︙ | |||
246 247 248 249 250 251 252 253 254 255 256 257 258 259 | upvar #0 [lindex $args 0] conn if {![::info exists conn(tls)]} { return -code error \ "\"[lindex $args 0]\" is not a ldap connection handle" } return $conn(tls) } proc ldap::info_saslmechanisms {args} { if {[llength $args] != 1} { return -code error \ "Wrong # of arguments. Usage: ldap::info saslmechanisms handle" } return [Saslmechanisms [lindex $args 0]] | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | upvar #0 [lindex $args 0] conn if {![::info exists conn(tls)]} { return -code error \ "\"[lindex $args 0]\" is not a ldap connection handle" } return $conn(tls) } #----------------------------------------------------------------------------- # return the TLS connection status # #----------------------------------------------------------------------------- proc ldap::info_tlsstatus {args} { if {[llength $args] != 1} { return -code error \ "Wrong # of arguments. Usage: ldap::info tlsstatus handle" } CheckHandle [lindex $args 0] upvar #0 [lindex $args 0] conn if {![::info exists conn(tls)]} { return -code error \ "\"[lindex $args 0]\" is not a ldap connection handle" } if {$conn(tls)} then { set r [::tls::status $conn(sock)] } else { set r {} } return $r } proc ldap::info_saslmechanisms {args} { if {[llength $args] != 1} { return -code error \ "Wrong # of arguments. Usage: ldap::info saslmechanisms handle" } return [Saslmechanisms [lindex $args 0]] |
︙ | ︙ | |||
386 387 388 389 390 391 392 393 394 395 396 397 | set conn(lastError) "" set conn(referenceVar) [namespace current]::searchReferences set conn(returnReferences) 0 fileevent $sock readable [list ::ldap::MessageReceiver ::ldap::ldap$sock] return ::ldap::ldap$sock } #----------------------------------------------------------------------------- # secure_connect # #----------------------------------------------------------------------------- | > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > > > > > | | | | | | | | | | | > | > > > > > > > > > > > > > > > > < < | | < | < | | < < < < | | | < < | < > > | 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 | set conn(lastError) "" set conn(referenceVar) [namespace current]::searchReferences set conn(returnReferences) 0 fileevent $sock readable [list ::ldap::MessageReceiver ::ldap::ldap$sock] return ::ldap::ldap$sock } #----------------------------------------------------------------------------- # tlsoptions # #----------------------------------------------------------------------------- proc ldap::tlsoptions {args} { variable curTLSOptions variable validTLSOptions variable defaultTLSOptions variable TLSMode if {$args eq "reset"} then { array set curTLSOptions [array get defaultTLSOptions] } else { foreach {opt val} $args { if {$opt in $validTLSOptions} then { set curTLSOptions($opt) $val } else { return -code error "invalid TLS option '$opt'" } } } set TLSMode "integrated" return [array get curTLSOptions] } #----------------------------------------------------------------------------- # secure_connect # #----------------------------------------------------------------------------- proc ldap::secure_connect { host {port 636} {verify_cert ""} {sni_servername ""}} { variable tlsProtocols variable curTLSOptions variable TLSMode package require tls #------------------------------------------------------------------ # set options #------------------------------------------------------------------ if {$TLSMode eq "compatible"} then { # # Compatible with old mode. Build a TLS socket with appropriate # parameters, without changing any other parameter which may # have been set by a previous call to tls::init (as specified # in the ldap.tcl manpage). # if {$verify_cert eq ""} then { set verify_cert 1 } set cmd [list tls::socket -request 1 -require $verify_cert \ -ssl2 no -ssl3 no] if {$sni_servername ne ""} { lappend cmd -servername $sni_servername } # The valid ones depend on the server and openssl version, # tls::ciphers all tells it in the error message, but offers no # nice introspection. foreach {proto active} $tlsProtocols { lappend cmd $proto $active } lappend cmd $host $port } else { # # New, integrated mode. Use only parameters set with # ldap::tlsoptions to build the socket. # if {$verify_cert ne "" || $sni_servername ne ""} then { return -code error "verify_cert/sni_servername: incompatible with the use of tlsoptions" } set cmd [list tls::socket {*}[array get curTLSOptions] $host $port] } #------------------------------------------------------------------ # connect via TCP/IP #------------------------------------------------------------------ set sock [eval $cmd] #------------------------------------------------------------------ # Run the TLS handshake # #------------------------------------------------------------------ # run the handshake in synchronous I/O mode fconfigure $sock -blocking yes -translation binary -buffering full if {[catch { tls::handshake $sock } err]} { close $sock return -code error $err } # from now on, run in asynchronous I/O mode fconfigure $sock -blocking no -translation binary -buffering full #-------------------------------------- # initialize connection array #-------------------------------------- upvar ::ldap::ldap$sock conn catch { unset conn } |
︙ | ︙ | |||
469 470 471 472 473 474 475 | #------------------------------------------------------------------------------ # starttls - negotiate tls on an open ldap connection # #------------------------------------------------------------------------------ proc ldap::starttls {handle {cafile ""} {certfile ""} {keyfile ""} \ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > | 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 | #------------------------------------------------------------------------------ # starttls - negotiate tls on an open ldap connection # #------------------------------------------------------------------------------ proc ldap::starttls {handle {cafile ""} {certfile ""} {keyfile ""} \ {verify_cert ""} {sni_servername ""}} { variable tlsProtocols variable curTLSOptions variable TLSMode CheckHandle $handle upvar #0 $handle conn #------------------------------------------------------------------ # set options #------------------------------------------------------------------ if {$TLSMode eq "compatible"} then { # # Compatible with old mode. Build a TLS socket with appropriate # parameters, without changing any other parameter which may # have been set by a previous call to tls::init (as specified # in the ldap.tcl manpage). # if {$verify_cert eq ""} then { set verify_cert 1 } set cmd [list tls::import $conn(sock) \ -cafile $cafile -certfile $certfile -keyfile $keyfile \ -request 1 -server 0 -require $verify_cert \ -ssl2 no -ssl3 no ] if {$sni_servername ne ""} { lappend cmd -servername $sni_servername } # The valid ones depend on the server and openssl version, # tls::ciphers all tells it in the error message, but offers no # nice introspection. foreach {proto active} $tlsProtocols { lappend cmd $proto $active } } else { # # New, integrated mode. Use only parameters set with # ldap::tlsoptions to build the socket. # if {$cafile ne "" || $certfile ne "" || $keyfile ne "" || $verify_cert ne "" || $sni_servername ne ""} then { return -code error "cafile/certfile/keyfile/verify_cert/sni_servername: incompatible with the use of tlsoptions" } set cmd [list tls::import $conn(sock) {*}[array get curTLSOptions]] } #------------------------------------------------------------------ # check handle #------------------------------------------------------------------ if {$conn(tls)} { return -code error \ "Cannot StartTLS on connection, TLS already running" } if {[ldap::waitingForMessages $handle]} { return -code error \ |
︙ | ︙ | |||
531 532 533 534 535 536 537 | if {$oid ne "1.3.6.1.4.1.1466.20037"} { set conn(tlsHandshakeInProgress) 0 return -code error \ "Unexpected LDAP response" } # Initiate the TLS socket setup | < < < < < < < < < < < | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | if {$oid ne "1.3.6.1.4.1.1466.20037"} { set conn(tlsHandshakeInProgress) 0 return -code error \ "Unexpected LDAP response" } # Initiate the TLS socket setup eval $cmd set retry 0 while {1} { if {$retry > 20} { close $sock |
︙ | ︙ |
Changes to modules/ldap/ldap.test.
︙ | ︙ | |||
252 253 254 255 256 257 258 259 260 261 262 263 264 265 | test ldap-28.0 {check wrong num args for ldap::disconnect } -body { ldap::disconnect } -returnCodes {error} \ -result [tcltest::wrongNumArgs {ldap::disconnect} \ {handle} 0 ] # ------------------------------------------------------------------------- # Handling of string representation of filters (RFC 4515): # ------------------------------------------------------------------------- proc glue args { join $args "" } | > > > > > > > | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | test ldap-28.0 {check wrong num args for ldap::disconnect } -body { ldap::disconnect } -returnCodes {error} \ -result [tcltest::wrongNumArgs {ldap::disconnect} \ {handle} 0 ] test ldap-29.0 {check invalid TLS option } -body { ldap::tlsoptions -foo bar } -returnCodes {error} \ -result {invalid TLS option '-foo'} # ------------------------------------------------------------------------- # Handling of string representation of filters (RFC 4515): # ------------------------------------------------------------------------- proc glue args { join $args "" } |
︙ | ︙ |
Changes to modules/ldap/ldapx.man.
|
| | | 1 2 3 4 5 6 7 8 | [vset VERSION 1.2] [comment {-*- tcl -*- doctools manpage}] [comment {$Id: ldapx.man,v 1.14 2009/01/29 06:16:19 andreas_kupries Exp $}] [manpage_begin ldapx n [vset VERSION]] [keywords {directory access}] [keywords internet] [keywords ldap] [keywords {ldap client}] |
︙ | ︙ | |||
404 405 406 407 408 409 410 | modified in nearly all methods). The [method error] method may be used to fetch this message. [list_end] [subsection {Ldap Options}] | > > > > > > > > > > > > > > > > > > > > > | | 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 | modified in nearly all methods). The [method error] method may be used to fetch this message. [list_end] [subsection {Ldap Options}] Options are configured on [class ldap] instances using the [cmd configure] method. [para] The first option is used for TLS parameters: [list_begin options] [opt_def -tlsoptions [arg list]] Specify the set of TLS options to use when connecting to the LDAP server (see the [cmd connect] method). For the list of valid options, see the [package LDAP] package documentation. [para] The default is [const {-request 1 -require 1 -ssl2 no -ssl3 no -tls1 yes -tls1.1 yes -tls1.2 yes}]. [para] Example: [para] [example {$l configure -tlsoptions {-request yes -require yes}}] [list_end] A set of options of the [class ldap] class is used during search operations (methods [method traverse], [method search] and [method read], see below). [list_begin options] [opt_def -scope [const base]|[const one]|[const sub]] |
︙ | ︙ | |||
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | [para] Default is {{.*} {}}, meaning: all attributes are converted, without exception. [list_end] [subsection {Ldap Methods}] [list_begin definitions] [call [arg la] [method error] [opt [arg newmsg]]] This method returns the error message that occurred in the last call to a [class ldap] class method. If the optional argument [arg newmsg] is supplied, it becomes the last error message. | > | > > > > > > > > > > > > > > | 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 | [para] Default is {{.*} {}}, meaning: all attributes are converted, without exception. [list_end] [subsection {Ldap Methods}] [list_begin definitions] [call [arg la] [method error] [opt [arg newmsg]]] This method returns the error message that occurred in the last call to a [class ldap] class method. If the optional argument [arg newmsg] is supplied, it becomes the last error message. [call [arg la] [method connect] [arg url] [opt [arg binddn]] [opt [arg bindpw]] [opt [arg starttls]]] This method connects to the LDAP server using given URL (which can be of the form [uri ldap://host:port] or [uri ldaps://host:port]). If an optional [arg binddn] argument is given together with the [arg bindpw] argument, the [method connect] binds to the LDAP server using the specified DN and password. [para] If the [arg starttls] argument is given a true value ([const 1], [const yes], etc.) and the URL uses the [uri ldap://] scheme, a TLS negotiation is initiated with the newly created connection, before LDAP binding. Default value: [const no]. [para] This method returns 1 if connection was successful, or 0 if an error occurred (use the [cmd error] method to get the message). [call [arg la] [method disconnect]] This method disconnects (and unbinds, if necessary) from the LDAP server. [call [arg la] [method traverse] [arg base] [arg filter] [arg attrs] [arg entry] [arg body]] |
︙ | ︙ | |||
558 559 560 561 562 563 564 | [subsection {Ldap Example}] [example { package require ldapx # | | > | | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 | [subsection {Ldap Example}] [example { package require ldapx # # Connects to the LDAP directory using StartTLS # ::ldapx::ldap create l l configure -tlsoptions {-cadir /etc/ssl/certs -request yes -require yes} set url "ldap://server.mycomp.com" if {! [l connect $url "cn=admin,o=mycomp" "mypasswd" yes]} then { puts stderr "error: [l error]" exit 1 } # # Search all entries matching some criterion # |
︙ | ︙ |
Changes to modules/ldap/ldapx.tcl.
1 2 3 | # # Extended object interface to entries in LDAP directories or LDIF files. # | | | | | 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 | # # Extended object interface to entries in LDAP directories or LDIF files. # # (c) 2006-2018 Pierre David (pdagog@gmail.com) # # $Id: ldapx.tcl,v 1.12 2008/02/07 21:19:39 pdav Exp $ # # History: # 2006/08/08 : pda : design # package require Tcl 8.4 package require snit ;# tcllib package require uri 1.1.5 ;# tcllib package require base64 ;# tcllib package require ldap 1.10 ;# tcllib, low level code for LDAP directories package provide ldapx 1.2 ############################################################################## # LDAPENTRY object type ############################################################################## snit::type ::ldapx::entry { ######################################################################### |
︙ | ︙ | |||
847 848 849 850 851 852 853 854 855 856 857 858 859 860 | option -scope -default "sub" option -derefaliases -default "never" option -sizelimit -default 0 option -timelimit -default 0 option -attrsonly -default 0 component translator delegate option -utf8 to translator # # Channel descriptor # | > > | 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 | option -scope -default "sub" option -derefaliases -default "never" option -sizelimit -default 0 option -timelimit -default 0 option -attrsonly -default 0 option -tlsoptions -default {} component translator delegate option -utf8 to translator # # Channel descriptor # |
︙ | ︙ | |||
902 903 904 905 906 907 908 | set lastError $le } return $lastError } # Connect to the LDAP directory, and binds to it if needed | | > > > > > > > > > > | | 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 | set lastError $le } return $lastError } # Connect to the LDAP directory, and binds to it if needed method connect {url {binddn {}} {bindpw {}} {starttls no}} { array set comp [::uri::split $url "ldap"] if {! [::info exists comp(host)]} then { $self error "Invalid host in URL '$url'" return 0 } # use ::ldap with integrated TLS mode ::ldap::tlsoptions reset ::ldap::tlsoptions {*}$options(-tlsoptions) set scheme $comp(scheme) if {! [::info exists connect_defaults($scheme)]} then { $self error "Unrecognized URL '$url'" return 0 } set defport [lindex $connect_defaults($scheme) 0] set fct [lindex $connect_defaults($scheme) 1] if {[string equal $comp(port) ""]} then { set comp(port) $defport } if {[Check $selfns {set channel [$fct $comp(host) $comp(port)]}]} then { return 0 } if {$starttls && [string equal $scheme "ldap"]} then { if {[Check $selfns {::ldap::starttls $channel}]} then { return 0 } } if {$binddn eq ""} then { set bind 0 } else { set bind 1 if {[Check $selfns {::ldap::bind $channel $binddn $bindpw}]} then { return 0 } } return 1 } # Disconnect from the LDAP directory method disconnect {} { Connected $selfns if {$bind} { |
︙ | ︙ |
Changes to modules/log/log.man.
︙ | ︙ | |||
132 133 134 135 136 137 138 | Compares two levels (including unique abbreviations) with respect to their priority. This command can be used by the -command option of lsort. The result is one of -1, 0 or 1 or an error. A result of -1 signals that level1 is of less priority than level2. 0 signals that both levels have the same priority. 1 signals that level1 has higher priority than level2. | | | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | Compares two levels (including unique abbreviations) with respect to their priority. This command can be used by the -command option of lsort. The result is one of -1, 0 or 1 or an error. A result of -1 signals that level1 is of less priority than level2. 0 signals that both levels have the same priority. 1 signals that level1 has higher priority than level2. [call [cmd ::log::lvSuppress] [arg level] "{[arg suppress] 1}"] (Un)suppresses the output of messages having the specified level. Unique abbreviations for the level are allowed here too. [call [cmd ::log::lvSuppressLE] [arg level] "{[arg suppress] 1}"] (Un)suppresses the output of messages having the specified level or one of lesser priority. Unique abbreviations for the level are allowed here too. [call [cmd ::log::lvIsSuppressed] [arg level]] |
︙ | ︙ |
Changes to modules/math/ChangeLog.
1 2 3 4 5 6 7 | 2018-07-22 Arjen Markus <[email protected]> * trig.tcl: Implementation of (additional) trigonometric functions - package math::trig * trig.test: Trst for the (additional) trigonometric functions * trig.man: Documentation for the (additional) trigonometric functions * pkgIndex.tcl: Add the new package 2018-07-19 Arjen Markus <[email protected]> | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | 2018-08-04 Arjen Markus <[email protected]> * statistics.tcl: Source stat_wasserstein.tcl and stat_logit.tcl - for new commands * statistics.test: Add corresponding tests * statistics.man: Add description of these commands * pkgIndex.tcl: Bump the version to 1.3.0 2018-07-22 Arjen Markus <[email protected]> * trig.tcl: Implementation of (additional) trigonometric functions - package math::trig * trig.test: Trst for the (additional) trigonometric functions * trig.man: Documentation for the (additional) trigonometric functions * pkgIndex.tcl: Add the new package 2018-07-19 Arjen Markus <[email protected]> |
︙ | ︙ |
Changes to modules/math/TODO.
1 2 3 4 5 6 7 8 | This file records outstanding actions for the math module dd. 17 june 2018 - Factor out the backward rotation in the intersection routines for circles - Add a normalisation routine for vectors - Add routines to construct a perpendicular vector and line - Add a routine to return the perpendicular bisector of a line segment - Add routines to deal with triangles (incircle, circumcircle) | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | This file records outstanding actions for the math module dd. 4 september 2018 - Implement a "typical profile" for timeseries and determining residuals (Plus perhaps a notion of outliers) - Implement detection of extreme values/periods with extreme values dd. 17 june 2018 - Factor out the backward rotation in the intersection routines for circles - Add a normalisation routine for vectors - Add routines to construct a perpendicular vector and line - Add a routine to return the perpendicular bisector of a line segment - Add routines to deal with triangles (incircle, circumcircle) |
︙ | ︙ |
Changes to modules/math/pkgIndex.tcl.
︙ | ︙ | |||
17 18 19 20 21 22 23 | package ifneeded math::bignum 3.1.1 [list source [file join $dir bignum.tcl]] package ifneeded math::bigfloat 1.2.2 [list source [file join $dir bigfloat.tcl]] package ifneeded math::machineparameters 0.1 [list source [file join $dir machineparameters.tcl]] if {![package vsatisfies [package provide Tcl] 8.5]} {return} package ifneeded math::calculus 0.8.1 [list source [file join $dir calculus.tcl]] # statistics depends on linearalgebra (for multi-variate linear regression). | > | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package ifneeded math::bignum 3.1.1 [list source [file join $dir bignum.tcl]] package ifneeded math::bigfloat 1.2.2 [list source [file join $dir bigfloat.tcl]] package ifneeded math::machineparameters 0.1 [list source [file join $dir machineparameters.tcl]] if {![package vsatisfies [package provide Tcl] 8.5]} {return} package ifneeded math::calculus 0.8.1 [list source [file join $dir calculus.tcl]] # statistics depends on linearalgebra (for multi-variate linear regression). # statistics depends on optimize (for logistic regression). package ifneeded math::statistics 1.3.0 [list source [file join $dir statistics.tcl]] package ifneeded math::linearalgebra 1.1.6 [list source [file join $dir linalg.tcl]] package ifneeded math::calculus::symdiff 1.0.1 [list source [file join $dir symdiff.tcl]] package ifneeded math::bigfloat 2.0.2 [list source [file join $dir bigfloat2.tcl]] package ifneeded math::numtheory 1.1.1 [list source [file join $dir numtheory.tcl]] package ifneeded math::decimal 1.0.3 [list source [file join $dir decimal.tcl]] package ifneeded math::geometry 1.3.0 [list source [file join $dir geometry.tcl]] package ifneeded math::trig 1.0 [list source [file join $dir trig.tcl]] |
︙ | ︙ |
Added modules/math/stat_logit.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | # stat_logit.tcl -- # Logistic regression functions - part of the statistics package # # Note: # The implementation was derived from the Wikipedia page on logistic regression, # (https://en.wikipedia.org/wiki/Logistic_regression) as is the test case. # # TODO: # - Deviance to evaluate the goodness of fit # - Evaluate the probability # package require math::optimize namespace eval ::math::statistics { variable xLogit {} variable yLogit {} } # logistic-model -- # Fit 1/0 data to a logistic model # # Arguments: # xdata Independent variables (list of lists if there are more than one) # ydata Corresponding scores (0 or 1) # # Result: # Estimate of the parameters for a logistic model # # Note: # It is expected that the independent variables have roughly the same scale # proc ::math::statistics::logistic-model {xdata ydata} { variable xLogit variable yLogit set xLogit {} foreach coords $xdata { lappend xLogit [concat 1.0 $coords] } set yLogit $ydata # # Use a trivial starting point # set startx [lrepeat [llength [lindex $xLogit 0]] 0.0] set result [::math::optimize::nelderMead LogisticML_NM $startx] return [dict get $result x] } # LogisticML_NM -- # Calculate the (log) maximum likelihood for the given logistic model # using Nelder-Mead # # Arguments: # args Vector of the current regression coefficients # # Returns: # Log maximum likelihood # proc ::math::statistics::LogisticML_NM {args} { variable xLogit variable yLogit set loglike 0.0 foreach coords $xLogit score $yLogit { set sum 0.0 foreach c $coords v $args { set sum [expr {$sum + $v * $c}] } set exp [expr {exp(-$sum)}] if { $score == 1 } { set loglike [expr {$loglike - log(1.0 + $exp)}] } else { set loglike [expr {$loglike - $sum - log(1.0 + $exp)}] } } return [expr {-$loglike}] } # logistic-probability -- # Calculate the probability of a positive score (1) given the model # # Arguments: # coeffs Coefficients of the logistic model (for instance outcome of model fit) # values Values of the independent variables # # Returns: # Probability # proc ::math::statistics::logistic-probability {coeffs values} { set sum 0.0 foreach c $coeffs v [concat 1.0 $values] { set sum [expr {$sum + $c * $v}] } return [expr {1.0 / (1.0 + exp(-$sum))}] } # test case: from Wikipedia if {0} { set xdata {0.50 0.75 1.00 1.25 1.50 1.75 1.75 2.00 2.25 2.50 2.75 3.00 3.25 3.50 4.00 4.25 4.50 4.75 5.00 5.50} set ydata {0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 } set coeffs [::math::statistics::logistic-model $xdata $ydata] puts "Model fit: $coeffs" puts "Probabilities:" foreach x {1 2 3 4 5} { puts "$x - [::math::statistics::logistic-probability $coeffs $x]" } } |
Added modules/math/stat_wasserstein.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | # stat-wasserstein.tcl -- # Determine the Wasserstein distance between two probability distributions # # Note: # This is an implementation for one-dimensional distributions (or better: # non-negative patterns) # # Note 2: # The lower bound of 1.0e-10 is probably not at all necessary # # LastNonZero -- # Auxiliary procedure to find the last non-zero entry # # Arguments: # prob Probability distribution # # Result: # Index in the list of the last non-zero entry # # Note: # To avoid numerical problems any value smaller than 1.0e-10 is considered to # be zero # proc ::math::statistics::LastNonZero {prob} { set maxidx [expr {[llength $prob] - 1}] for {set idx $maxidx} {$idx >= 0} {incr idx -1} { if { [lindex $prob $idx] > 1.0e-10 } { return $idx } } return -1 ;# No non-zero entry } # Normalise -- # Auxiliary procedure to normalise the probability distribution # # Arguments: # prob Probability distribution # # Result: # Normalised distribution (i.e. the entries sum to 1) # # Note: # To avoid numerical problems any value smaller than 1.0e-10 is set to zero # proc ::math::statistics::Normalise {prob} { set newprob {} set sum 0.0 foreach p $prob { set sum [expr {$sum + $p}] } if { $sum == 0.0 } { return -code error "Probability distribution should not consist of only zeroes" } foreach p $prob { lappend newprob [expr {$p > 1.0e-10? ($p/$sum) : 0.0}] } return $newprob } # wasserstein-distance -- # Determine the Wasserstein distance using a "greedy" algorithm. # # Arguments: # prob1 First probability distribution, interpreted as a histogram # with uniform bin width # prob2 Second probability distribution # # Result: # Distance between the two distributions # proc ::math::statistics::wasserstein-distance {prob1 prob2} { # # First step: make sure the histograms have the same length and the # same cumulative weight. # if { [llength $prob1] != [llength $prob2] } { return -code error "Lengths of the probability histograms must be the same" } set prob1 [Normalise $prob1] set prob2 [Normalise $prob2] set distance 0.0 # # Determine the last non-zero bin - this bin will be shifted to the second # distribution # while {1} { set idx1 [LastNonZero $prob1] set idx2 [LastNonZero $prob2] if { $idx1 < 0 } { break ;# We are done } set bin1 [lindex $prob1 $idx1] set bin2 [lindex $prob2 $idx2] if { $bin1 <= $bin2 } { lset prob1 $idx1 0.0 lset prob2 $idx2 [expr {$bin2 - $bin1}] set distance [expr {$distance + abs($idx2-$idx1) * $bin1}] } else { lset prob1 $idx1 [expr {$bin1 - $bin2}] lset prob2 $idx2 0.0 set distance [expr {$distance + abs($idx2-$idx1) * $bin2}] } } return $distance } # kl-divergence -- # Calculate the Kullback-Leibler (KL) divergence for two discrete distributions # # Arguments: # prob1 First probability distribution - the divergence is calculated # with this one as the basis # prob2 Second probability distribution - the divergence of this # distribution wrt the first is calculated # # Notes: # - The KL divergence is an asymmetric measure # - It is actually only defined if prob2 is only zero when prob1 is too # - The number of elements in the two distributions must be the same and # bins must be the same # proc ::math::statistics::kl-divergence {prob1 prob2} { if { [llength $prob1] != [llength $prob2] } { return -code error "Lengths of the two probability histograms must be the same" } # # Normalise the probability histograms # set prob1 [Normalise $prob1] set prob2 [Normalise $prob2] # # Check for well-definedness while going along # set sum 0.0 foreach p1 $prob1 p2 $prob2 { if { $p2 == 0.0 && $p1 != 0.0 } { return -code error "Second probability histogram contains unmatched zeroes" } if { $p1 != 0.0 } { set sum [expr {$sum - $p1 * log($p2/$p1)}] } } return $sum } if {0} { # tests -- # # Almost trivial set prob1 {0.0 0.0 0.0 1.0} set prob2 {0.0 0.0 1.0 0.0} puts "Expected distance: 1" puts "Calculated: [wasserstein-distance $prob1 $prob2]" puts "Symmetric: [wasserstein-distance $prob2 $prob1]" # Less trivial set prob1 {0.0 0.75 0.25 0.0} set prob2 {0.0 0.0 1.0 0.0} puts "Expected distance: 0.75" puts "Calculated: [wasserstein-distance $prob1 $prob2]" puts "Symmetric: [wasserstein-distance $prob2 $prob1]" # Shift trivial set prob1 {0.0 0.1 0.2 0.4 0.2 0.1 0.0 0.0} set prob2 {0.0 0.0 0.0 0.1 0.2 0.4 0.2 0.1} puts "Expected distance: 2" puts "Calculated: [wasserstein-distance $prob1 $prob2]" puts "Symmetric: [wasserstein-distance $prob2 $prob1]" # KL-divergence set prob1 {0.0 0.1 0.2 0.4 0.2 0.1 0.0 0.0} set prob2 {0.0 0.1 0.2 0.4 0.2 0.1 0.0 0.0} puts "KL-divergence for equal distributions: 0" puts "KL-divergence: [kl-divergence $prob1 $prob2]" set prob1 {0.1e-8 0.1 0.2 0.4 0.2 0.1 0.0 0.0 0.0} set prob2 {0.1e-8 0.1e-8 0.1 0.2 0.4 0.2 0.1 0.1e-8 0.1e-8} puts "KL-divergence for shifted distributions: ??" puts "KL-divergence: [kl-divergence $prob1 $prob2]" # Hm, the normalisation proc causes a slight problem with elements of 1.0e-10 set prob1 {0.1e-8 0.1 0.2 0.4 0.2 0.1 0.0 0.0} set prob2 {0.1e-8 0.11 0.19 0.4 0.24 0.06 0.1e-8 0.1e-8} puts "KL-divergence slightly dififerent distributions: ??" puts "KL-divergence: [kl-divergence $prob1 $prob2]" } |
Changes to modules/math/statistics.man.
1 2 3 4 5 6 7 8 | [vset VERSION 1] [manpage_begin math::statistics n [vset VERSION]] [keywords {data analysis}] [keywords mathematics] [keywords statistics] [moddesc {Tcl Math Library}] [titledesc {Basic statistical functions and procedures}] [category Mathematics] | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [vset VERSION 1] [manpage_begin math::statistics n [vset VERSION]] [keywords {data analysis}] [keywords mathematics] [keywords statistics] [moddesc {Tcl Math Library}] [titledesc {Basic statistical functions and procedures}] [category Mathematics] [require Tcl 8.5] [require math::statistics [vset VERSION]] [description] [para] The [package math::statistics] package contains functions and procedures for basic statistical data analysis, such as: |
︙ | ︙ | |||
324 325 326 327 328 329 330 | [arg_def list args] - One or more groups of data to be checked [list_end] [para] [call [cmd ::math::statistics::quantiles] [arg data] [arg confidence]] Return the quantiles for a given set of data [list_begin arguments] | < | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | [arg_def list args] - One or more groups of data to be checked [list_end] [para] [call [cmd ::math::statistics::quantiles] [arg data] [arg confidence]] Return the quantiles for a given set of data [list_begin arguments] [arg_def list data] - List of raw data values [para] [arg_def float confidence] - Confidence level (0.95 or 0.99 for instance) or a list of confidence levels. [para] [list_end] [para] |
︙ | ︙ | |||
615 616 617 618 619 620 621 622 623 624 625 626 627 628 | is returned (as a list of "sampleSize" values), otherwise a list of samples is returned. [list_begin arguments] [arg_def list data] List of values to chose from [arg_def int sampleSize] Number of values per sample [arg_def int numberSamples] Number of samples (default: 1) [list_end] [list_end] [section "MULTIVARIATE LINEAR REGRESSION"] Besides the linear regression with a single independent variable, the statistics package provides two procedures for doing ordinary | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | is returned (as a list of "sampleSize" values), otherwise a list of samples is returned. [list_begin arguments] [arg_def list data] List of values to chose from [arg_def int sampleSize] Number of values per sample [arg_def int numberSamples] Number of samples (default: 1) [list_end] [call [cmd ::math::statistics::wasserstein-distance] [arg prob1] [arg prob2]] Compute the Wasserstein distance or earth mover's distance for two equidstantly spaced histograms or probability densities. The histograms need not to be normalised to sum to one, but they must have the same number of entries. [nl] Note: the histograms are assumed to be based on the same equidistant intervals. As the bounds are not passed, the value is expressed in the length of the intervals. [list_begin arguments] [arg_def list prob1] List of values for the first histogram/probability density [arg_def list prob2] List of values for the second histogram/probability density [list_end] [call [cmd ::math::statistics::kl-divergence] [arg prob1] [arg prob2]] Compute the Kullback-Leibler (KL) divergence for two equidstantly spaced histograms or probability densities. The histograms need not to be normalised to sum to one, but they must have the same number of entries. [nl] Note: the histograms are assumed to be based on the same equidistant intervals. As the bounds are not passed, the value is expressed in the length of the intervals. [nl] Note also that the KL divergence is not symmetric and that the second histogram should not contain zeroes in places where the first histogram has non-zero values. [list_begin arguments] [arg_def list prob1] List of values for the first histogram/probability density [arg_def list prob2] List of values for the second histogram/probability density [list_end] [call [cmd ::math::statistics::logistic-model] [arg xdata] [arg ydata]] Estimate the coefficients of the logistic model that fits the data best. The data consist of independent x-values and the outcome 0 or 1 for each of the x-values. The result can be used to estimate the probability that a certain x-value gives 1. [list_begin arguments] [arg_def list xdata] List of values for which the success (1) or failure (0) is known [arg_def list ydata] List of successes or failures corresponding to each value in [term xdata]. [list_end] [call [cmd ::math::statistics::logistic-probability] [arg coeffs] [arg x]] Calculate the probability of success for the value [term x] given the coefficients of the logistic model. [list_begin arguments] [arg_def list coeffs] List of coefficients as determine by the [cmd logistic-model] command [arg_def float x] X-value for which the probability needs to be determined [list_end] [list_end] [section "MULTIVARIATE LINEAR REGRESSION"] Besides the linear regression with a single independent variable, the statistics package provides two procedures for doing ordinary |
︙ | ︙ | |||
1531 1532 1533 1534 1535 1536 1537 | ::math::statistics::plot-scale .plot1 0 100 0 20 ::math::statistics::plot-scale .plot2 0 20 0 20 ::math::statistics::plot-tline .plot1 $data1 ::math::statistics::plot-tline .plot1 $data2 ::math::statistics::plot-xydata .plot2 $data1 $data2 puts "Correlation coefficient:" | | | 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 | ::math::statistics::plot-scale .plot1 0 100 0 20 ::math::statistics::plot-scale .plot2 0 20 0 20 ::math::statistics::plot-tline .plot1 $data1 ::math::statistics::plot-tline .plot1 $data2 ::math::statistics::plot-xydata .plot2 $data1 $data2 puts "Correlation coefficient:" puts [lb]::math::statistics::corr $data1 $data2[rb] pause 2 puts "Plot histograms" .plot2 delete all ::math::statistics::plot-scale .plot2 0 20 0 100 set limits [lb]::math::statistics::minmax-histogram-limits 7 16[rb] set histogram_data [lb]::math::statistics::histogram $limits $data1[rb] |
︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 | .plot2 itemconfigure d2 -fill red puts "Second series:" print-histogram $histogram_data $limits puts "Autocorrelation function:" set autoc [lb]::math::statistics::autocorr $data1[rb] | | | 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 | .plot2 itemconfigure d2 -fill red puts "Second series:" print-histogram $histogram_data $limits puts "Autocorrelation function:" set autoc [lb]::math::statistics::autocorr $data1[rb] puts [lb]::math::statistics::map $autoc {[lb]format "%.2f" $x[rb]}[rb] puts "Cross-correlation function:" set crossc [lb]::math::statistics::crosscorr $data1 $data2[rb] puts [lb]::math::statistics::map $crossc {[lb]format "%.2f" $x[rb]}[rb] ::math::statistics::plot-scale .plot1 0 100 -1 4 ::math::statistics::plot-tline .plot1 $autoc "autoc" ::math::statistics::plot-tline .plot1 $crossc "crossc" |
︙ | ︙ |
Changes to modules/math/statistics.tcl.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 | # version 0.7: added Kruskal-Wallis test (by Torsten Berg) # version 0.8: added Wilcoxon test and Spearman rank correlation # version 0.9: added kernel density estimation # version 0.9.3: added histogram-alt, corrected test-normal # version 1.0: added test-anova-F # version 1.0.1: correction in pdf-lognormal and cdf-lognormal # version 1.1: added test-Tukey-range and test-Dunnett package require Tcl 8.5 ; # 8.5+ feature in test-anovo-F: **-operator | > | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # version 0.7: added Kruskal-Wallis test (by Torsten Berg) # version 0.8: added Wilcoxon test and Spearman rank correlation # version 0.9: added kernel density estimation # version 0.9.3: added histogram-alt, corrected test-normal # version 1.0: added test-anova-F # version 1.0.1: correction in pdf-lognormal and cdf-lognormal # version 1.1: added test-Tukey-range and test-Dunnett # version 1.3: added wasserstein-distance, kl-divergence and logit regression package require Tcl 8.5 ; # 8.5+ feature in test-anovo-F: **-operator package provide math::statistics 1.3.0 package require math if {![llength [info commands ::lrepeat]]} { # Forward portability, emulate lrepeat proc ::lrepeat {n args} { if {$n < 1} { return -code error "must have a count of at least 1" |
︙ | ︙ | |||
1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 | source [file join [file dirname [info script]] pdf_stat.tcl] source [file join [file dirname [info script]] plotstat.tcl] source [file join [file dirname [info script]] liststat.tcl] source [file join [file dirname [info script]] mvlinreg.tcl] source [file join [file dirname [info script]] kruskal.tcl] source [file join [file dirname [info script]] wilcoxon.tcl] source [file join [file dirname [info script]] stat_kernel.tcl] # # Define the tables # namespace eval ::math::statistics { variable tukey_table_05 variable tukey_table_01 | > > | 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 | source [file join [file dirname [info script]] pdf_stat.tcl] source [file join [file dirname [info script]] plotstat.tcl] source [file join [file dirname [info script]] liststat.tcl] source [file join [file dirname [info script]] mvlinreg.tcl] source [file join [file dirname [info script]] kruskal.tcl] source [file join [file dirname [info script]] wilcoxon.tcl] source [file join [file dirname [info script]] stat_kernel.tcl] source [file join [file dirname [info script]] stat_wasserstein.tcl] source [file join [file dirname [info script]] stat_logit.tcl] # # Define the tables # namespace eval ::math::statistics { variable tukey_table_05 variable tukey_table_01 |
︙ | ︙ |
Changes to modules/math/statistics.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | testsNeedTcl 8.5;# statistics,linalg! testsNeedTcltest 2.1 support { useLocal math.tcl math useLocal linalg.tcl math::linearalgebra } testing { useLocal statistics.tcl math::statistics } # ------------------------------------------------------------------------- | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | testsNeedTcl 8.5;# statistics,linalg! testsNeedTcltest 2.1 support { useLocal math.tcl math useLocal linalg.tcl math::linearalgebra useLocal optimize.tcl math::optimize } testing { useLocal statistics.tcl math::statistics } # ------------------------------------------------------------------------- |
︙ | ︙ | |||
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 | set result 0 } } set result } -result 1 # End of test cases testsuiteCleanup | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 | set result 0 } } set result } -result 1 # # Tests for Wasserstein distance and KL divergence # # Tests for error conditions # test "Wasserstein-1.1" "Error: lengths differ" -body { set distance [::math::statistics::wasserstein-distance {0 1} {1 0 0 0}] } -returnCodes 1 -result {Lengths of the probability histograms must be the same} # # Check the symmetry for arbitrary histograms # test "Wasserstein-1.2" "Test symmetry" -body { set okay 1 for {set i 0} {$i < 10} {incr i} { set histogram1 {} set histogram2 {} for {set j 0} {$j < 3*($i+1)} {incr j} { lappend histogram1 [expr {rand()}] lappend histogram2 [expr {rand()}] } set distance1 [::math::statistics::wasserstein-distance $histogram1 $histogram2] set distance2 [::math::statistics::wasserstein-distance $histogram2 $histogram1] if { abs($distance1-$distance2) > 1.0e-6 } { set okay 0 } } return $okay } -result 1 # # Check the non-negativity for arbitrary histograms # test "Wasserstein-1.3" "Test non-negativity" -body { set okay 1 for {set i 0} {$i < 10} {incr i} { set histogram1 {} set histogram2 {} for {set j 0} {$j < 3*($i+1)} {incr j} { lappend histogram1 [expr {rand()}] lappend histogram2 [expr {rand()}] } set distance1 [::math::statistics::wasserstein-distance $histogram1 $histogram2] if { $distance1 < 0.0 } { set okay 0 } } return $okay } -result 1 # # Check the non-normalised histograms # test "Wasserstein-1.4" "Test non-normalised histograms" -match tolerant -body { return [list [::math::statistics::wasserstein-distance {2 0 0} {0 0 0.5}] \ [::math::statistics::wasserstein-distance {1 0 0} {0 0 0.25}] ] } -result {2.0 2.0} # # Check arbitrarily extended histograms # test "Wasserstein-1.5" "Test extended histograms" -match tolerant -body { return [list [::math::statistics::wasserstein-distance {1 0 0} {0 0 1}] \ [::math::statistics::wasserstein-distance {0 0 1 0 0} {0 0 0 0 1}] \ [::math::statistics::wasserstein-distance {1 0 0 0 0} {0 0 1 0 0}] ] } -result {2.0 2.0 2.0} # # Check numerical results # test "Wasserstein-1.6" "Test numerical results" -match tolerant -body { return [list [::math::statistics::wasserstein-distance {1 0 0} {0 0.5 0.5}] \ [::math::statistics::wasserstein-distance {1 0 0 0 0} {0 0 0 0.5 0.5}] \ [::math::statistics::wasserstein-distance {1 0 0 0 0} {0 0.25 0.25 0.25 0.25}] ] } -result {1.5 3.5 2.5} # # Tests for error conditions # test "KL-divergence-1.1" "Error: lengths differ" -body { set distance [::math::statistics::kl-divergence {0 1} {1 0 0 0}] } -returnCodes 1 -result {Lengths of the two probability histograms must be the same} test "KL-divergence-1.2" "Error: unmatched zeroes" -body { set distance [::math::statistics::kl-divergence {0.3 0.3 0.4} {1 0 0}] } -returnCodes 1 -result {Second probability histogram contains unmatched zeroes} test "KL-divergence-1.3" "Matched zeroes should be accepted" -match tolerant -body { set distance [::math::statistics::kl-divergence {0.3 0.3 0.4 0} {0.7 0.2 0.1 0}] } -returnCodes 0 -result 0.42196792 # # Tests for equal histograms (not all normalised) # test "KL-divergence-1.4" "Equal histograms give zero divergence" -body { set distance [::math::statistics::kl-divergence {0.3 0.3 0.4} {0.3 0.3 0.4}] } -result 0.0 test "KL-divergence-1.5" "Non-normalised but equal histograms give zero divergence" -body { set distance [::math::statistics::kl-divergence {0.3 0.3 0.4} {0.6 0.6 0.8}] } -result 0.0 # # Numerical tests - note: the expected values were taken from the implementation # No independent source found # test "KL-divergence-1.6" "Shifted histograms" -match tolerant -body { set distance [::math::statistics::kl-divergence {1.0e-8 0.3 0.3 0.3 0.1} {0.3 0.3 0.3 0.1 1.0e-8}] } -result 1.9413931 test "KL-divergence-1.7" "Arbitrary histograms" -match tolerant -body { set distance [::math::statistics::kl-divergence {0.4 0.2 0.3 0.1} {0.1 0.1 0.7 0.1}] } -result 0.4389578 # # Tests for logistic regression # set xdata {0.50 0.75 1.00 1.25 1.50 1.75 1.75 2.00 2.25 2.50 2.75 3.00 3.25 3.50 4.00 4.25 4.50 4.75 5.00 5.50} set ydata {0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 } test "Logit-regression-1.0" "Logistic regression - coefficients" -match tolerant -body { set coeffs [::math::statistics::logistic-model $xdata $ydata] } -result {-4.07679035286303 1.5045982920571572} test "Logit-regression-1.1" "Logistic regression - probabilities" -match tolerant -body { set coeffs [::math::statistics::logistic-model $xdata $ydata] set probabilities {} foreach x {1 2 3 4 5} { lappend probabilities [::math::statistics::logistic-probability $coeffs $x] } return $probabilities } -result {0.07094967663389527 0.2558609520815849 0.6075450376084848 0.8745281239093334 0.9691176473773739} # End of test cases testsuiteCleanup |
Changes to modules/mime/mime.man.
︙ | ︙ | |||
13 14 15 16 17 18 19 | [keywords {rfc 822}] [keywords {rfc 2045}] [keywords {rfc 2046}] [keywords {rfc 2049}] [keywords smtp] [copyright {1999-2000 Marshall T. Rose}] [moddesc {Mime}] | | | < < < | < < < < | < | < < < < < < < < < < < < | | < | < | < < < < | < < < | < < < | < < < | < < < < < < < < | < < < < | < | < | < < | < | < < | < | < < | < < < < < < < < < < < < < < < < < < < | < | < < < | | < | < < | < | < | < < | < < < < < < < < | < | < < < < < | < | < < | < < | < < < | < | < < < < < < < < < < < < | < < < < < < < | < < < < < | | < < < < < < < < < < < < | < | < | < | < | < < < | < < < < < < < < < | < | < < < | < < | < < < < < < < < < < < < < < | | 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 | [keywords {rfc 822}] [keywords {rfc 2045}] [keywords {rfc 2046}] [keywords {rfc 2049}] [keywords smtp] [copyright {1999-2000 Marshall T. Rose}] [moddesc {Mime}] [titledesc {Manipulation of Internet messages}] [category {Text processing}] [require Tcl 8.5] [require mime [opt 1.6]] [description] [para] Provides commands to create and manipulate Internet messages. [list_begin definitions] [call [cmd ::mime::initialize] [ opt "[option -canonical] [arg type/subtype]"] [ opt "[option -params] [arg dictionary]"] [ opt "[option -encoding] [arg value]"] [ opt "[option -headers] [arg dictionary]"] [ opt "([option -chan] [arg name] | [option -file] [arg name] | [ option -string] [arg value] | [option -parts] [arg parts])"]] Parses a message and returns a token for the message. One of [ option -chan ], [ option -file ], or [ option -string ] must be provided as the source of the input. If [ option -canonical ] is provided the input is the body only and is already formatted according to the provided [ arg type/subtype ], and therefore should not be parsed. If [ arg parts ] is provided it is a list of tokens for messages that comprise a [ const multipart/mixed ] message body. [ option -params ] is a multidict (a dictionary where the keys may not be unique) of parameters for the [ const Content-Type ] header. [ option -headers ] is a multidict of headers. [para] [option -encoding] sets the [const Content-Transfer-Encoding]. [call [cmd ::mime::body] [arg token] [opt [option -decode]] [opt "[option -blocksize] [arg octets]"]"] Returns as a string in canonical form the body of the message corresponding to [arg token]. [para] If [option -blocksize] is provided, returns a command that itself returns up to the next [arg octets] of the message each time it's called, and returns a code of [const break] when finished, deleting itself as well. If [arg octets] is the empty string, a default value is used. Pauses the current coroutine as needed to wait for input. [para] [option -decode] converts the message body from the character set it is encoded in. [call [cmd ::mime::datetime] ([arg time] | [option -now]) [arg property]] Returns the [arg property] of [arg time], which 822-style date-time value. [para] Available properties and their ranges are: [list_begin definitions] [def [const hour]] 0 .. 23 |
︙ | ︙ | |||
359 360 361 362 363 364 365 366 367 368 | 1900 ... [def [const zone]] -720 .. 720 (minutes east of GMT) [list_end] [call [cmd ::mime::mapencoding] [arg encoding_name]] | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > | 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 | 1900 ... [def [const zone]] -720 .. 720 (minutes east of GMT) [list_end] [call [cmd ::mime::finalize] [arg token] [opt "[option -subordinates] [const all] | [const dynamic] | [const none]"]] Destroys the message corresponding to [arg token] and returns the empty string. [para] [option -subordinates] specifies which messages comprising the body should also be destroyed. The default value is [const dynamic], which destroys all component messages that were created by [cmd ::mime::initialize]. [call [cmd ::mime::header] [cmd serialize] [arg value] [arg parameters]] Serialize a header. [call [cmd ::mime::header] [cmd get] [arg token] [opt "[arg key] | [option -names]"]] Returns the header of a message as a multidict where each value is a list containing the header value and any parameters for that value. [para] If [arg name] is provided returns a list of values for that name, without regard to case. [para] If [option -names] is provided, returns a list of all header names. [call [cmd ::mime::header] [cmd set] [arg token] [arg {name value}] [ \ opt "[arg parameters] [opt "[option -mode] [const write] | [\ const append] | [const delete]"]"]] If [const append] is provided, creates a new header named [arg name] with the value of [arg value] is added. If [const write] is provided, deletes any existing headers whose names match [arg key] and then creates a new header named [arg key] with the value of [arg value]. If [const delete] is provided, deletes any existing header having a name that matches [arg key]. [arg parameters] is a dictionary of parameters for the header. Returns a list of strings containing the previous value associated with the key. [para] The value for [option -mode] is one of: [list_begin definitions] [def [const write]] The [arg key]/[arg value] is either created or overwritten (the default). [def [const append]] Appends a new [arg key]/[arg value]. [def [const delete]] Removes all values associated with the key. [arg value] is ignored. [list_end] [call [cmd ::mime::property] [arg token] [opt "[arg name] | [option -names]"]] Returns a dictionary of message properties. If [arg name] is provided, only the corresponding value is returned. If [option -names] is provided, a list of all property names is returned. [para] properties: [list_begin definitions] [def [const content]] The type/subtype of the content [def [const encoding]] The "Content-Transfer-Encoding" [def [const params]] A list of "Content-Type" parameters [def [const parts]] A list of tokens for messages that should comprise a multipart body. Only exists if there are any such messages. [def [const size]] The approximate size of the unencoded content. [list_end] [call [cmd ::mime::serialize] [arg token] [opt "[option -chan] [arg channel]"]] Return the serialization of the message corresponding to [arg token]. If [option -chan] is provided, write the message to [arg channel] and return the empty string. Pauses the current coroutine as needed to wait for input to become available. [call [cmd ::mime::parseaddress] [arg addresses]] Returns a list of describing the comma-separated 822-style [arg addresses]. [para] Each dictionary contains the following keys, whose values may be the empty string: [list_begin definitions] [def [const address]] local@domain [def [const comment]] 822-style comment [def [const domain]] the domain part (rhs) [def [const error]] non-empty on a parse error [def [const group]] this address begins a group [def [const friendly]] user-friendly rendering [def [const local]] the local part (lhs) [def [const memberP]] this address belongs to a group [def [const phrase]] the phrase part [def [const proper]] 822-style address specification [def [const route]] 822-style route specification (obsolete) [list_end] [call [cmd ::mime::mapencoding] [arg encoding_name]] Maps Tcl encodings onto the proper names for their MIME charset type. This is only done for encodings whose charset types were known. The remaining encodings return "" for now. [call [cmd ::mime::reversemapencoding] [arg charset_type]] Maps MIME charset types onto tcl encoding names. Those that are unknown return "". [list_end] [section {KNOWN BUGS}] [list_begin definitions] [def {Tcllib Bug #447037}] This problem affects only people which are using Tcl and Mime on a 64-bit system. The currently recommended fix for this problem is to upgrade to Tcl version 8.4. This version has extended 64 bit support and the bug does not appear anymore. [para] The problem could have been generally solved by requiring the use of Tcl 8.4 for this package. We decided against this solution as it would force a large number of unaffected users to upgrade their Tcl interpreter for no reason. [para] See [uri {/tktview?name=447037} {Ticket 447037}] for additional information. [list_end] [vset CATEGORY mime] [include ../doctools2base/include/feedback.inc] [manpage_end] |
Changes to modules/mime/mime.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 | # mime.tcl - MIME body parts # # (c) 1999-2000 Marshall T. Rose # (c) 2000 Brent Welch # (c) 2000 Sandeep Tamhankar # (c) 2000 Dan Kuchler # (c) 2000-2001 Eric Melski # (c) 2001 Jeff Hobbs # (c) 2001-2008 Andreas Kupries # (c) 2002-2003 David Welton # (c) 2003-2008 Pat Thoyts # (c) 2005 Benjamin Riefenstahl | | | > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # mime.tcl - MIME body parts # # (c) 1999-2000 Marshall T. Rose # (c) 2000 Brent Welch # (c) 2000 Sandeep Tamhankar # (c) 2000 Dan Kuchler # (c) 2000-2001 Eric Melski # (c) 2001 Jeff Hobbs # (c) 2001-2008 Andreas Kupries # (c) 2002-2003 David Welton # (c) 2003-2008 Pat Thoyts # (c) 2005 Benjamin Riefenstahl # (c) 2013-2018 PoorYorick # # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Influenced by Borenstein's/Rose's safe-tcl (circa 1993) and Darren New's # unpublished package of 1999. # # new string features and inline scan are used, requiring 8.3. package require Tcl 8.6 package require tcl::chan::memchan package require tcl::chan::string package require coroutine namespace eval ::mime { namespace path ::coroutine::util {*}[namespace path] } package require sha256 package provide mime 1.7 if {[catch {package require Trf 2.0}]} { # Fall-back to tcl-based procedures of base64 and quoted-printable encoders # Warning! # These are a fragile emulations of the more general calling sequence # that appears to work with this code here. |
︙ | ︙ | |||
62 63 64 65 66 67 68 | unset ::major } # # state variables: # # canonicalP: input is in its canonical form | < < | > > < < < < < < < < < < < < < < | 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 | unset ::major } # # state variables: # # canonicalP: input is in its canonical form # encoding: transfer encoding # version: MIME-version # header: dicttionary (keys are lower-case) # lowerL: list of header keys, lower-case # mixedL: list of header keys, mixed-case # value: either "file", "parts", or "string" # # file: input file # fd: cached file-descriptor, typically for root # root: token for top-level part, for (distant) subordinates # offset: number of octets from beginning of file/string # count: length in octets of (encoded) content # # parts: list of bodies (tokens) # # string: input string # # cid: last child-id assigned # namespace eval ::mime { variable mime array set mime {uid 0 cid 0} # RFC 822 lexemes variable addrtokenL lappend addrtokenL \; , < > : . ( ) @ \" \[ ] \\ variable addrlexemeL { LX_SEMICOLON LX_COMMA LX_LBRACKET LX_RBRACKET LX_COLON LX_DOT LX_LPAREN LX_RPAREN LX_ATSIGN LX_QUOTE LX_LSQUARE LX_RSQUARE LX_QUOTE } variable encList { ascii US-ASCII big5 Big5 cp1250 Windows-1250 cp1251 Windows-1251 cp1252 Windows-1252 cp1253 Windows-1253 |
︙ | ︙ | |||
323 324 325 326 327 328 329 | ksc5601 KS_C_5601-1989 ksc5601 KSC5601 ksc5601 korean shiftjis MS_Kanji utf-8 UTF8 } | | > | > > | | > > > > > > > > > > | | > > > > | | > > > > | > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > | > | | | > | > > | > > > < < > | < < < | < < < < < < | < | < < < < < < < < < < < < < < | < < < < < | > > > > > > | > | > > > > > > > > > | > > > > | | > | | | | | < | | > | > > > | < | < < | | < < | | | | < < < < < | < < > < | | | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < < < < < < < < < < | < < < | | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < | | < < < < < < < < < < | < < < < < < < < < | < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | | | | < | | < | | < < < | | 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 | ksc5601 KS_C_5601-1989 ksc5601 KSC5601 ksc5601 korean shiftjis MS_Kanji utf-8 UTF8 } namespace export {*}{ datetime finalize getbody header initialize mapencoding parseaddress property reversemapencoding serialize setheader uniqueID } } proc ::mime::addchan {token fd} { variable channels upvar 0 $token state if {[info exists state(fd)]} { error [list {a channel is already present}] } set state(fd) $fd incr channels($fd) return } proc ::mime::contentid {} { set unique [uniqueID] return $unique@| } proc ::mime::dropchan token { variable channels upvar 0 $token state upvar 0 state(fd) fd if {[info exists fd]} { if {[incr channels($fd) -1] == 0} { unset channels($fd) if {$state(closechan)} { close $fd } } unset state(fd) } } # ::mime::initialize -- # # the public interface for initializeaux proc ::mime::initialize args { variable mime set token [namespace current]::[incr mime(uid)] # FRINK: nocheck upvar 0 $token state if {[catch [list mime::initializeaux $token {*}$args] result eopts]} { catch {mime::finalize $token -subordinates dynamic} return -options $eopts $result } return $token } # ::mime::initializeaux -- # # Creates a MIME part, and returnes the MIME token for that part. # # Arguments: # args Args can be any one of the following: # ?-canonical type/subtype # ?-params {?key value? ...} # ?-encoding value? # ?-headers {?key value? ...} # ?-http # (-file name | -string value | -parts {token1 ... tokenN}) # # If the -canonical option is present, then the body is in # canonical (raw) form and is found by consulting either the -file, # -string, or -parts option. # # -header # a dictionary of headers # with possibliy-redundant keys # -http # operate in http mode # # -params # a dictionary of parameters # with possibly-redundant keys # # # Also, -encoding, if present, specifies the # "Content-Transfer-Encoding" when copying the body. # # If the -canonical option is not present, then the MIME part # contained in either the -file or the -string option is parsed, # dynamically generating subordinates as appropriate. # # Results: # An initialized mime token. proc ::mime::initializeaux {token args} { variable channels # FRINK: nocheck upvar 0 $token state upvar 0 state(canonicalP) canonicalP upvar 0 state(params) params set params {} set state(hparams) {} set state(encoding) {} set state(version) 1.0 set state(bodyparsed) 0 set canonicalP 0 set state(header) {} set state(headerparsed) 0 set state(lowerL) {} set state(mixedL) {} set state(cid) 0 set state(closechan) 1 set userparams 0 set argc [llength $args] for {set argx 0} {$argx < $argc} {incr argx} { set option [lindex $args $argx] if {[incr argx] >= $argc} { error "missing argument to $option" } set value [lindex $args $argx] switch $option { -canonical { set canonicalP 1 set type [string tolower $value] } -chan { set state(file) {} addchan $token $value } -close { set state(closechan) [expr {!!$value}] } -params { if {$userparams} { error [list {-params can only be provided once}] } set userparams 1 if {[llength $value] % 2} { error [list -params expects a dictionary] } foreach {mixed pvalue} $value { set lower [string tolower $mixed] if {[dict exists params $lower]} { error "the $mixed parameter may be specified at most once" } dict set params $lower $pvalue } } -encoding { set value [string tolower $value[set value {}]] switch $value { 7bit - 8bit - binary - quoted-printable - base64 { } default { error "unknown value for -encoding $state(encoding)" } } set state(encoding) [string tolower $value] } -headers { # process headers later in order to assure that content-id and # content-type occur first if {[info exists headers]} { error [list {-headers option occurred more than once}] } if {[llength $value] % 2} { error [list -headers expects a dictionary] } set headers $value } -file { set state(file) $value } -parts { set canonicalP 1 set state(parts) $value } -string { set state(string) $value set state(lines) [split $value \n] set state(lines.count) [llength $state(lines)] set state(lines.current) 0 } -root { # the following are internal options set state(root) $value } -offset { set state(offset) $value } -count { set state(count) $value } -lineslist { set state(lines) $value set state(lines.count) [llength $state(lines)] set state(lines.current) 0 #state(string) is needed, but will be built when required set state(string) {} } default { error [list {unknown option} $option] } } } #We only want one of -chan -file, -parts or -string: set valueN 0 foreach value {file parts string} { if {[info exists state($value)]} { set state(value) $value incr valueN } } if {$valueN != 1 && ![info exists state(lines)]} { error [list {specify exactly one of} {-file -parts -string}] } if {$state(value) eq {file}} { if {[info exists state(root)]} { # FRINK: nocheck upvar 0 $state(root) root addchan $token $root(fd) } else { set state(root) $token if {![info exists state(fd)]} { addchan $token [open $state(file) RDONLY] } set state(offset) 0 seek $state(fd) 0 end set state(count) [tell $state(fd)] fconfigure $state(fd) -translation binary } } if {$canonicalP} { if {![header exists $token content-id]} { header::setinternal $token Content-ID [contentid] } if {![info exists type]} { set type multipart/mixed } header setinternal $token Content-Type $type $params if {[info exists headers]} { foreach {name hvalue} $headers { set lname [string tolower $name] if {$lname eq {content-type}} { error [list {use -canonical instead of -headers} $hkey $name] } if {$lname eq {content-transfer-encoding}} { error [list {use -encoding instead of -headers} $hkey $name] } if {$lname in {content-md5 mime-version}} { error [list {don't go there...}] } header::setinternal $token $name $hvalue } } lassign [header get $token content-type] content switch $state(value) { file { set state(offset) 0 } parts { switch -glob $content { text/* - image/* - audio/* - video/* { error "-canonical $content and -parts do not mix" } default { if {$state(encoding) ne {}} { error "-encoding and -parts do not mix" } } } } default {# Go ahead} } set state(version) 1.0 return } if {[dict size $params]} { error "-param requires -canonical" } if {$state(encoding) ne {}} { error "-encoding requires -canonical" } if {[info exists headers]} { error "-header requires -canonical" } } # ::mime::parsepart -- # # Parses the MIME headers and attempts to break up the message # into its various parts, creating a MIME token for each part. # # Arguments: # token The MIME token to parse. # # Results: # Throws an error if it has problems parsing the MIME token, # otherwise it just sets up the appropriate variables. proc ::mime::parsepartaux token { # FRINK: nocheck upvar 0 $token state upvar 0 state(last) last header parse $token if {![header exists $token content-type]} { header setinternal $token Content-Type text/plain [ dict create charset us-ascii] } lassign [header get $token content-type] content params set fileP [info exists state(file)] if {![string match multipart/* $content]} { if {$fileP} { set x [tell $state(fd)] incr state(count) [expr {$state(offset) - $x}] set state(offset) $x } else { # rebuild string, this is cheap and needed by other functions set state(string) [join [ lrange $state(lines) $state(lines.current) end] \n] } if {[string match message/* $content]} { # FRINK: nocheck variable [set child $token-[incr state(cid)]] set state(value) parts set state(parts) $child if {$fileP} { mime::initializeaux $child \ -file $state(file) -root $state(root) \ -offset $state(offset) -count $state(count) } else { if {[info exists state(encoding)]} { set strng [join [ lrange $state(lines) $state(lines.current) end] \n] switch $state(encoding) { base64 - quoted-printable { set strng [$state(encoding) -mode decode -- $strng] } default {} } mime::initializeaux $child -string $strng } else { mime::initializeaux $child -lineslist [ lrange $state(lines) $state(lines.current) end] } } } return } set state(value) parts dict update params boundary boundary {} if {![info exists boundary]} { error "boundary parameter is missing in $content" } if {[string trim $boundary] eq {}} { error "boundary parameter is empty in $content" } if {$fileP} { set pos [tell $state(fd)] # This variable is like 'start', for the reasons laid out # below, in the other branch of this conditional. set initialpos $pos |
︙ | ︙ | |||
844 845 846 847 848 849 850 | # application/octet-stream regardless of header # information. set line "--$boundary--" set x [string length $line] set forceoctet 1 } else { if {[set x [gets $state(fd) line]] < 0} { | | | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 | # application/octet-stream regardless of header # information. set line "--$boundary--" set x [string length $line] set forceoctet 1 } else { if {[set x [gets $state(fd) line]] < 0} { error "end-of-file encountered while parsing $content" } } incr pos [expr {$x + 1}] } else { if {$state(lines.current) >= $state(lines.count)} { error "end-of-string encountered while parsing $content" } else { set line [lindex $state(lines) $state(lines.current)] incr state(lines.current) set x [string length $line] } set x [string length $line] } |
︙ | ︙ | |||
921 922 923 924 925 926 927 | } } # Looking for the end of the current part. We accept both a # terminating boundary and the starting boundary of the next # part as the end of the current part. | | | > | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 | } } # Looking for the end of the current part. We accept both a # terminating boundary and the starting boundary of the next # part as the end of the current part. if {[set moreP [string compare $line --$boundary--]] && $line ne "--$boundary"} { # The current part has not ended, so we record the line # if we are inside a part and doing string parsing. if {$inP && !$fileP} { lappend start $line } continue } |
︙ | ︙ | |||
946 947 948 949 950 951 952 | set nochild 0 if {$fileP} { if {[set count [expr {$pos - ($start + $x + $crlf + 1)}]] < 0} { set count 0 } if {$forceoctet} { | < > > | > > | > < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | set nochild 0 if {$fileP} { if {[set count [expr {$pos - ($start + $x + $crlf + 1)}]] < 0} { set count 0 } if {$forceoctet} { if {[catch { mime::initializeaux $child \ -file $state(file) -root $state(root) \ -offset $start -count $count parsepart $child }]} { set nochild 1 set state(parts) [lrange $state(parts) 0 end-1] } } else { mime::initializeaux $child \ -file $state(file) -root $state(root) \ -offset $start -count $count parsepart $child } seek $state(fd) [set start $pos] start } else { if {$forceoctet} { if {[catch { mime::initializeaux $child -lineslist $start parsepart $child } cres copts]} { set nochild 1 set state(parts) [lrange $state(parts) 0 end-1] } } else { mime::initializeaux $child -lineslist $start parsepart $child } set start {} } if {$forceoctet && !$nochild} { header setinternal $child Content-Type application/octet-stream } set forceoctet 0 } } # ::mime::finalize -- # # mime::finalize destroys a MIME part. # # If the -subordinates option is present, it specifies which # subordinates should also be destroyed. The default value is # "dynamic". # # Arguments: # token The MIME token to parse. # args Args can be optionally be of the following form: # ?-subordinates "all" | "dynamic" | "none"? # # Results: # Returns an empty string. proc ::mime::finalize {token args} { # FRINK: nocheck upvar 0 $token state array set options [list -subordinates dynamic] array set options $args switch $options(-subordinates) { all { #TODO: this code path is untested if {$state(value) eq "parts"} { foreach part $state(parts) { eval [linsert $args 0 mime::finalize $part] } } |
︙ | ︙ | |||
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 | none { } default { error "unknown value for -subordinates $options(-subordinates)" } } foreach name [array names state] { unset state($name) } # FRINK: nocheck unset $token } | > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | < > > | | | > | > > | > > > > > | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > | > > | > > > > > > > > > | > > > > > > > | > > | | | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 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 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 | none { } default { error "unknown value for -subordinates $options(-subordinates)" } } dropchan $token foreach name [array names state] { unset state($name) } # FRINK: nocheck unset $token } # ::mime::getsize -- # # Determine the size (in bytes) of a MIME part/token # # Arguments: # token The MIME token to parse. # # Results: # Returns the size in bytes of the MIME token. proc ::mime::getsize {token} { # FRINK: nocheck upvar 0 $token state switch $state(value)/$state(canonicalP) { file/0 { set size $state(count) } file/1 { return [file size $state(file)] } parts/0 - parts/1 { set size 0 foreach part $state(parts) { incr size [getsize $part] } return $size } string/0 { set size [string length $state(string)] } string/1 { return [string length $state(string)] } default { error [list {Unknown combination} $state(value) $state(canonicalP)] } } if {$state(encoding) eq {base64}} { set size [expr {($size * 3 + 2) / 4}] } return $size } proc ::mime::getTransferEncoding token { upvar 0 $token state set res {} if {[set encoding $state(encoding)] eq {}} { set encoding [encoding $token] } if {$encoding ne {}} { set res $encoding } switch $encoding { base64 - quoted-printable { set converter $encoding } 7bit - 8bit - binary - {} { # Bugfix for [#477088], also [#539952] # Go ahead } default { error "Can't handle content encoding \"$encoding\"" } } return $res } namespace eval ::mime::header { namespace ensemble create -map { get get exists exists parse parse set set_ serialize serialize setinternal setinternal } variable tchar # hypen is first for inclusion in brackets variable tchar_re {-!#$%&'*+.^`|~0-9A-Za-z} variable token_re "^(\[$tchar_re]*)\\s*(?:;|$)?" variable notattchar_re "\[^[string map {* {} ' {} % {}} $tchar_re]]" # RFC 2045 lexemes variable typetokenL lappend typetokenL \; , < > : ? ( ) @ \" \[ ] = / \\ variable typelexemeL { LX_SEMICOLON LX_COMMA LX_LBRACKET LX_RBRACKET LX_COLON LX_QUESTION LX_LPAREN LX_RPAREN LX_ATSIGN LX_QUOTE LX_LSQUARE LX_RSQUARE LX_EQUALS LX_SOLIDUS LX_QUOTE } variable internal 0 } proc ::mime::header::boundary {} { return [uniqueID] } proc ::mime::header::serialize {token name value params} { variable notattchar_re set lname [string tolower $name] # to do: check key for conformance # to do: properly quote/process $value for interpolation if {[regexp {[^\x21-\x39\x3b-\x7e]} $name]} { error [ list {non-printing character or colon character in header name} $name] } if {[regexp {[^\t\x20-\x7e]} $value]} { error [ list {non-printing character in header value}] } switch $lname { content-id - message-id { set value <$value> } } set res "$name: $value" dict for {key value} $params { if {[regexp $notattchar_re $key]} { error [list {illegal character found in attribute name}] } set len [expr {[string length $key]} + 1 + [string length $value]] # save one byte for the folding white space continuation space # and two bytes for "; " if {$len > 73 || ![regexp {[^-!#$%&'*+,.\w`~^@{}|]+$} $value]} { # save two bytes for the quotes if {$len <= 71 && ![regexp {[^\x20-\x7e]} $value]} { set value "[string map [list \\ \\\\ \" \\\"] $value[set value {}]]" append res "\n\t; $key=$value" } else { set value [::encoding convertto utf-8 $value] regsub -all -- $notattchar_re $value {[format %%%02X [scan "\\&" %c]]} value set value [subst -novariables $value] set partnum 0 set start 0 set param $key*$partnum*=utf-8'' while {$start < [string length $value]} { # subtract one from the limit to ensure that at least one byte # is included in the part value if {[string length $param] > 72} { error [list {parameter name is too long}] } set end [expr {$start + 72 - [string length $param]}] set part [string range $value $start $end] incr start [string length $part] append res "\n\t; $param$part" set param $key*$partnum= incr partnum } } } else { append res "\n\t; $key=$value" } } return $res } proc ::mime::header::exists {token name} { upvar 0 $token state set lname [string tolower $name] dict exists $state(header) $lname } # ::mime::header get -- # # [mime::header get] returns the header of a MIME part. # # A header consists of zero or more key/value pairs. Each value is a # list containing one or more strings. # # If [mime::header get] is invoked with the name of a specific key, then # a list containing the corresponding value(s) is returned; instead, # if -names is specified, a list of all keys is returned; otherwise, a # dictionary is returned. Note that when a # key is specified (e.g., "Subject"), the list returned usually # contains exactly one string; however, some keys (e.g., "Received") # often occur more than once in the header, accordingly the list # returned usually contains more than one string. # # Arguments: # token The MIME token to parse. # key Either a key or '-names'. If it is '-names' a list # of all keys is returned. # # Results: # Returns the header of a MIME part. proc ::mime::header::get {token {key {}}} { # FRINK: nocheck upvar 0 $token state upvar 0 state(hparams) hparams parse $token array set header $state(header) switch $key { {} { set result {} lappend result MIME-Version [list $state(version) {}] foreach lower $state(lowerL) mixed $state(mixedL) { foreach value $header($lower) hparam [ dict get $hparams $lower] { lappend result $mixed [list $value $hparam] } } set tencoding [getTransferEncoding $token] if {$tencoding ne {}} { lappend result Content-Transfer-Encoding [list $tencoding {}] } return $result } -names { return $state(mixedL) } default { set lower [string tolower $key] switch $lower { content-transfer-encoding { return [list [getTransferEncoding $token] {}] } mime-version { return [list $state(version) {}] } default { if {![info exists header($lower)]} { error "key $key not in header" } return [list $header($lower) [lindex [ dict get $hparams $lower] end]] } } } } } proc ::mime::header::parse token { # FRINK: nocheck upvar 0 $token state if {$state(canonicalP) || $state(headerparsed)} { return } set state(headerparsed) 1 upvar 0 state(last) last if {[set fileP [info exists state(file)]]} { seek $state(fd) [set pos $state(offset)] start set last [expr {$state(offset) + $state(count) - 1}] } else { set string $state(string) } set vline {} while 1 { set blankP 0 if {$fileP} { if {($pos > $last) || ([set x [gets $state(fd) line]] <= 0)} { set blankP 1 } else { incr pos [expr {$x + 1}] } } else { if {$state(lines.current) >= $state(lines.count)} { set blankP 1 set line {} } else { set line [lindex $state(lines) $state(lines.current)] incr state(lines.current) set x [string length $line] if {$x == 0} {set blankP 1} } } if {!$blankP && [string match *\r $line]} { set line [string range $line 0 $x-2] if {$x == 1} { set blankP 1 } } # there is a space and a tab between the brackets in next line if {!$blankP && [string match {[ ]*} $line]} { append vline { } [string trimleft $line " \t"] continue } if {$vline eq {}} { if {$blankP} { break } set vline $line continue } if { [set x [string first : $vline]] <= 0 || [set mixed [string trimright [ string range $vline 0 [expr {$x - 1}]]]] eq {} } { error [list {improper line in header} $vline] } set value [string trim [string range $vline [expr {$x + 1}] end]] switch [set lower [string tolower $mixed]] { content-disposition { set_ $token $mixed {*}[parseparts $token $value] } content-type { if {[exists $token content-type]} { error [list {multiple Content-Type fields starting with} \ $vline] } set x [parsetype $token $value] setinternal $token Content-Type {*}$x } content-md5 { } content-transfer-encoding { if { $state(encoding) ne {} && $state(encoding) ne [string tolower $value] } { error [list [list multiple Content-Transfer-Encoding \ fields starting with] $vline] } set state(encoding) [string tolower $value] } mime-version { set state(version) $value } default { setinternal $token $mixed $value -mode append } } if {$blankP} { break } set vline $line } } proc ::mime::header::parseparams token { # FRINK: nocheck upvar 0 $token state set params {} while 1 { switch [parselexeme $token] { LX_END { return [processparams $params[set params {}]] } LX_SEMICOLON { if {[dict size $params]} { continue } else { error [list {expecting attribute} not $state(buffer)] } } LX_ATOM { } default { error [list {expecting attribute} not $state(buffer)] } } set attribute [string tolower $state(buffer)] if {[parselexeme $token] ne {LX_EQUALS}} { error [list expecting = found $state(buffer)] } switch [parselexeme $token] { LX_ATOM { } LX_QSTRING { set state(buffer) [ string range $state(buffer) 1 [ expr {[string length $state(buffer)] - 2}]] } default { error [list expecting value found $state(buffer)] } } dict set params $attribute $state(buffer) } } proc ::mime::header::parseparts {token value} { variable token_re upvar 0 $token state if {![regexp $token_re $value match type]} { error [list {expected disposition-type}] } variable typetokenL variable typelexemeL set value [string range $value[set value {}] [string length $match] end] set state(input) $value set state(buffer) {} set state(lastC) LX_END set state(comment) {} set state(tokenL) $typetokenL set state(lexemeL) $typelexemeL set code [catch {parseparams $token} result copts] unset {*}{ state(input) state(buffer) state(lastC) state(comment) state(tokenL) state(lexemeL) } return -options $copts [list $type $result] } # ::mime::header::parsetype -- # # Parses the string passed in and identifies the content-type and # params strings. # # Arguments: # token The MIME token to parse. # string The content-type string that should be parsed. # # Results: # Returns the content and params for the string as a two element # tcl list. proc ::mime::header::parsetype {token string} { # FRINK: nocheck upvar 0 $token state variable typetokenL variable typelexemeL set state(input) $string set state(buffer) {} set state(lastC) LX_END set state(comment) {} set state(tokenL) $typetokenL set state(lexemeL) $typelexemeL catch {parsetypeaux $token} result copts unset {*}{ state(input) state(buffer) state(lastC) state(comment) state(tokenL) state(lexemeL) } return -options $copts $result } # ::mime::header::parsetypeaux -- # # A helper function for mime::parsetype. Parses the specified # string looking for the content type and params. # # Arguments: # token The MIME token to parse. # string The content-type string that should be parsed. # # Results: # Returns the content and params for the string as a two element # tcl list. proc ::mime::header::parsetypeaux token { # FRINK: nocheck upvar 0 $token state set params {} if {[parselexeme $token] ne {LX_ATOM}} { error [list expecting type found $state(buffer)] } set type [string tolower $state(buffer)] switch [parselexeme $token] { LX_SOLIDUS { } LX_END { if {$type ne {message}} { error [list expecting type/subtype found $type] } return [list message/rfc822 {}] } default { error [list expecting / found $state(buffer)] } } if {[parselexeme $token] ne {LX_ATOM}} { error [list expecting subtype found $state(buffer)] } append type [string tolower /$state(buffer)] switch [parselexeme $token] { LX_END { } LX_SEMICOLON { set params [parseparams $token] } default { error [list expecting {; or end} found $state(buffer)] } } list $type $params } proc ::mime::header::processparams params { set info {} foreach key [lsort -dictionary [dict keys $params]] { set pvalue [dict get $params $key] # a trailing asterisk is ignored if this is not the first field in an # identically-named series # this expression can't fail regexp {^([^*]+?)(?:([*])([0-9]+))?([*])?$} $key -> name star1 counter star2 dict update info $name dict1 { if {![info exists dict1]} { set dict1 {} } dict update dict1 encoding encoding value value { if {$star1 ne {}} { if {$star2 ne {} || $counter eq {}} { if {![regexp {^([^']*)'([^']*)'(.*)$} $pvalue \ -> charset lang pvalue]} { error [list [list malformed language information in \ extended parameter name]] } if {$charset ne {}} { set encoding [reversemapencoding $charset] } } } append value $pvalue } } } set params {} dict for {key pinfo} $info[set info {}] { dict update pinfo encoding encoding value value {} if {[info exists encoding]} { set value [string map {% {\x}} $value[set value {}]] set value [subst -novariables -nocommands $value[set value {}]] set value [encoding convertfrom $encoding $value] } dict set params $key $value } return $params } # ::mime::header::set -- # # mime::header::set writes, appends to, or deletes the value associated # with a key in the header. # # The value for -mode is one of: # # write: the key/value is either created or overwritten (the # default); # |
︙ | ︙ | |||
1398 1399 1400 1401 1402 1403 1404 | # value The value for the header key to be set to. # args An optional argument of the form: # ?-mode "write" | "append" | "delete"? # # Results: # Returns previous value associated with the specified key. | | > < > > | | > > | < < | < < < < < | | | > | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > > > | > > > < < < < > > > > > > > > > | | | | | < | < < < > > > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > > > > > > > > > > > | > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | < < < < < | < | < < < < < < < < < < < | < < | < | | < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | < < < | < < | < < < < | < < < < < < < < < < < | | | < | 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 | # value The value for the header key to be set to. # args An optional argument of the form: # ?-mode "write" | "append" | "delete"? # # Results: # Returns previous value associated with the specified key. proc ::mime::header::set_ {token key value args} { variable internal # FRINK: nocheck upvar 0 $token state upvar 0 state(hparams) hparams parse $token set params {} switch [llength $args] { 1 - 3 { set args [lassign $args[set args {}] params] } 0 - 2 { # carry on } default { error [list {wrong # args}] } } array set options [list -mode write] array set options $args set lower [string tolower $key] array set header $state(header) if {[set x [lsearch -exact $state(lowerL) $lower]] < 0} { #TODO: this code path is not tested if {$options(-mode) eq "delete"} { error "key $key not in header" } lappend state(lowerL) $lower lappend state(mixedL) $key set result {} } else { set result $header($lower) } switch $options(-mode) { append - write { switch $lower { content-md5 - content-transfer-encoding - mime-version - content-type { if {!$internal} { switch $lower { default { lassign [get $token $lower] values params1 if {$value ni $values} { error "key $key may not be set" } } } } switch $lower { content-type { if {[string match multipart/* $value] && ![dict exists $params boundary] } { dict set params boundary [boundary] } } default { #carry on } } } } switch $options(-mode) { append { lappend header($lower) $value dict lappend hparams $lower $params } write { set header($lower) [list $value] dict set hparams $lower [list $params] } } } delete { unset header($lower) dict unset hparams $lower set state(lowerL) [lreplace $state(lowerL) $x $x] set state(mixedL) [lreplace $state(mixedL) $x $x] } default { error "unknown value for -mode $options(-mode)" } } set state(header) [array get header] return $result } proc ::mime::header::setinternal args { variable internal 1 try { set_ {*}$args } finally { set internal 0 } } # ::mime::body -- # # mime::body returns the body of a leaf MIME part in canonical form. # # If the -command option is present, then it is repeatedly invoked # with a fragment of the body as this: # # uplevel #0 $callback [list "data" $fragment] # # (The -blocksize option, if present, specifies the maximum size of # each fragment passed to the callback.) # When the end of the body is reached, the callback is invoked as: # # uplevel #0 $callback "end" # # Alternatively, if an error occurs, the callback is invoked as: # # uplevel #0 $callback [list "error" reason] # # Regardless, the return value of the final invocation of the callback # is propagated upwards by mime::body. # # If the -command option is absent, then the return value of # mime::body is a string containing the MIME part's entire body. # # Arguments: # token The MIME token to parse. # args Optional arguments of the form: # ?-decode? ?-command callback ?-blocksize octets? ? # # Results: # Returns a string containing the MIME part's entire body, or # if '-command' is specified, the return value of the command # is returned. proc ::mime::body {token args} { # FRINK: nocheck parsepart $token set decode 0 if {[set pos [lsearch -exact $args -decode]] >= 0} { set decode 1 set args [lreplace $args $pos $pos] } array set options $args if {[info exists options(-blocksize)]} { set collect 1 if {$options(-blocksize) eq {}]} { set options(-blocksize) 8192 } if {$options(-blocksize) < 1} { error [list -blocksize $options(-blocksize) {not a positive integer}] } } else { set options(-blocksize) 8192 set collect 0 } set coro [coroutine [info cmdcount]_body body2 $token $decode [array get options]] set command [list ::apply [list coro { return {*}[yieldto $coro [info coroutine]] } [namespace current]] $coro] if {$collect} { return $command } else { set res {} while 1 { append res [{*}$command] } return $res } } proc ::mime::body2 {token decode optdict} { set caller [yield [info coroutine]] set yield [list ::apply [list args { upvar 1 caller caller decode decode dread dread dwrite dwrite if {[llength $args] == 1 && [info exists decode] && $decode} { lassign $args[set args {}] fragment puts -nonewline $dwrite $fragment set arg {} # not using a coroutine::util::read here because there isn't much # data on the channel and if no characters are currently available, # the current routine must continue to put more data into the # channel. # $dread must be nonblocking even though it is read in a tight loop # here. while {[set data [::read $dread]] ne {}} { append arg $data } if {$arg ne {}} { lappend args $arg set caller [yieldto $caller {*}$args] } } else { set caller [yieldto $caller {*}$args] } } [namespace current]]] set return [list ::apply [list args { upvar 1 caller caller yield yield if {[info exists dread]} { close $dread close $dwrite } rename [info coroutine] {} uplevel 1 [list {*}$yield {*}$args] } [namespace current]]] try { upvar 0 $token state array set options $optdict set code 0 set ecode {} set einfo {} switch $state(value) { file { upvar 0 state(fd) fd set offset $state(offset) set count $state(count) } string { set offset 0 set fd [tcl::chan::string $state(string)] seek $fd 0 end set count [tell $fd] seek $fd 0 } } switch $state(value) { parts { error [list {MIME part isn't a leaf}] } } if {$decode} { lassign [chan pipe] dread dwrite chan configure $dread -blocking 0 chan configure $dwrite -blocking 0 -encoding binary -buffering none set params [mime::property $token params] if {[dict exists $params charset]} { set charset [dict get $params charset] } else { set charset US-ASCII } set enc [reversemapencoding $charset] if {$enc ne {}} { chan configure $dread -encoding $enc } else { {*}$return -code error [ list {-decode cannot reversemap charset} $charset] } } if {$state(canonicalP)} { seek $fd [set pos $offset] start fconfigure $fd -translation binary set code [catch { while {[string length [ set fragment [read $fd $options(-blocksize)]]] > 0} { {*}$yield $fragment } } result copts] } else { set code [catch { seek $fd [set pos $offset] start set last [expr {$offset + $count - 1}] set fragment {} while {$pos <= $last} { if {[set cc [ expr {($last - $pos) + 1}]] > $options(-blocksize)} { set cc $options(-blocksize) } incr pos [set len [ string length [set chunk [read $fd $cc]]]] switch -exact $state(encoding) { base64 - quoted-printable { if {([set x [string last \n $chunk]] > 0) \ && ($x + 1 != $len)} { set chunk [string range $chunk 0 $x] seek $fd [incr pos [expr {($x + 1) - $len}]] start } set chunk [ $state(encoding) -mode decode -- $chunk] } 7bit - 8bit - binary - {} { # Bugfix for [#477088] # Go ahead, leave chunk alone } default { error "Can't handle content encoding \"$state(encoding)\"" } } append fragment $chunk set cc [expr {$options(-blocksize) - 1}] while {[string length $fragment] > $options(-blocksize)} { {*}$yield [string range $fragment 0 $cc] set fragment [ string range $fragment $options(-blocksize) end] } } if {[string length $fragment] > 0} { {*}$yield $fragment } } result copts] } if {$code} { {*}$yield -options $copts $result } {*}$return -code break } on error {tres topts} { {*}$return -options $topts $tres } } # ::mime::bodyaux -- # # Builds up the body of the message, fragment by fragment. When # the entire message has been retrieved, it is returned. # # Arguments: # token The MIME token to parse. # reason One of 'data', 'end', or 'error'. # fragment The section of data data fragment to extract a # string from. # # Results: # Returns nothing, except when called with the 'end' argument # in which case it returns a string that contains all of the # data that 'bodyaux' has been called with. Will throw an # error if it is called with the reason of 'error'. proc ::mime::bodyaux {token reason {fragment {}}} { # FRINK: nocheck upvar 0 $token state switch $reason { data { append state(getbody) $fragment return {} } |
︙ | ︙ | |||
1720 1721 1722 1723 1724 1725 1726 | default { error "Unknown reason \"$reason\"" } } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < > > > | | > > > > > | | | | | | | | | | | | | < | > | > > > > | | < | | | | | | | < < < | 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 | default { error "Unknown reason \"$reason\"" } } } # ::mime::encoding -- # # Determines how a token is encoded. # # Arguments: # token The MIME token to parse. # # Results: # Returns the encoding of the message (the null string, base64, # or quoted-printable). proc ::mime::encoding token { # FRINK: nocheck upvar 0 $token state upvar 0 state(params) params lassign [header get $token content-type] content switch -glob $content { audio/* - image/* - video/* { return base64 } message/* - multipart/* { return {} } default {# Skip} } set asciiP 1 set lineP 1 switch $state(value) { file { if {$state(file) eq {}} { # choose a workable all-purpose encoding set asciiP 0 set lineP 0 } else { set fd [open $state(file) RDONLY] fconfigure $fd -translation binary while {[gets $fd line] >= 0} { if {$asciiP} { set asciiP [encodingasciiP $line] } if {$lineP} { set lineP [encodinglineP $line] } if {(!$asciiP) && (!$lineP)} { break } } catch {close $fd} } } parts { return {} } string { set saved $state(lines.current) while {$state(lines.current) < $state(lines.count)} { set line [lindex $state(lines) $state(lines.current)] incr state(lines.current) if {$asciiP} { set asciiP [encodingasciiP $line] } if {$lineP} { set lineP [encodinglineP $line] } if {(!$asciiP) && (!$lineP)} { break } } set state(lines.current) $saved } default { error [list {Unknown value} $state(value)] } } switch -glob $content { text/* { if {!$asciiP} { #TODO: this path is not covered by tests if {[dict exists $params charset]} { set v [string tolower [dict get $params $charset]] if {($v ne "us-ascii") \ && (![string match {iso-8859-[1-8]} $v])} { return base64 } } } if {!$lineP} { return quoted-printable } } |
︙ | ︙ | |||
2327 2328 2329 2330 2331 2332 2333 | # Arguments: # line The line to check. # # Results: # Returns 1 if \r only occurs at the end of lines, and if all # characters in the line are between the ASCII codes of 32 and 126. | | | > | > | > | < | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < | < > | < | | > > > > | > | < < < < | | | 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 | # Arguments: # line The line to check. # # Results: # Returns 1 if \r only occurs at the end of lines, and if all # characters in the line are between the ASCII codes of 32 and 126. proc ::mime::encodingasciiP line { foreach c [split $line {}] { switch $c { { } - \t - \r - \n { } default { binary scan $c c c if {($c < 32) || ($c > 126)} { return 0 } } } } if { [set r [string first \r $line]] < 0 || $r == {[string length $line] - 1} } { return 1 } return 0 } # ::mime::encodinglineP -- # # Checks if a string is a line is valid to be processed. # # Arguments: # line The line to check. # # Results: # Returns 1 the line is less than 76 characters long, the line # contains more characters than just whitespace, the line does # not start with a '.', and the line does not start with 'From '. proc ::mime::encodinglineP line { if {([string length $line] > 76) \ || ($line ne [string trimright $line]) \ || ([string first . $line] == 0) \ || ([string first {From } $line] == 0)} { return 0 } return 1 } proc ::mime::parsepart token { upvar 0 $token state if {$state(canonicalP) || $state(bodyparsed)} { return } set state(bodyparsed) 1 parsepartaux $token } # ::mime::qp_encode -- # # Tcl version of quote-printable encode # # Arguments: # string The string to quote. # encoded_word Boolean value to determine whether or not encoded words # (RFC 2047) should be handled or not. (optional) # # Results: # The properly quoted string is returned. proc ::mime::qp_encode {string {encoded_word 0} {no_softbreak 0}} { # 8.1+ improved string manipulation routines used. # Replace outlying characters, characters that would normally # be munged by EBCDIC gateways, and special Tcl characters "[\]{} # with =xx sequence if {$encoded_word} { # Special processing for encoded words (RFC 2047) set regexp {[\x00-\x08\x0B-\x1E\x21-\x24\x3D\x40\x5B-\x5E\x60\x7B-\xFF\x09\x5F\x3F]} lappend mapChars { } _ } else { set regexp {[\x00-\x08\x0B-\x1E\x21-\x24\x3D\x40\x5B-\x5E\x60\x7B-\xFF]} } regsub -all -- $regexp $string {[format =%02X [scan "\\&" %c]]} string # Replace the format commands with their result set string [subst -novariables $string] # soft/hard newlines and other # Funky cases for SMTP compatibility lappend mapChars " \n" =20\n \t\n =09\n \n\.\n =2E\n "\nFrom " "\n=46rom " set string [string map $mapChars $string] # Break long lines - ugh # Implementation of FR #503336 if {$no_softbreak} { set result $string |
︙ | ︙ | |||
2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 | set result [string replace $result end end =20] } elseif {$lastChar eq "\t"} { set result [string replace $result end end =09] } return $result } # ::mime::qp_decode -- # # Tcl version of quote-printable decode # # Arguments: # string The quoted-prinatble string to decode. | > | 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 | set result [string replace $result end end =20] } elseif {$lastChar eq "\t"} { set result [string replace $result end end =09] } return $result } # ::mime::qp_decode -- # # Tcl version of quote-printable decode # # Arguments: # string The quoted-prinatble string to decode. |
︙ | ︙ | |||
2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 | regsub -all -nocase {=([a-f0-9][a-f0-9])} $string {\\u00\1} string # process \u unicode mapped chars return [subst -novariables -nocommands $string] } # ::mime::parseaddress -- # # This was originally written circa 1982 in C. we're still using it # because it recognizes virtually every buggy address syntax ever # generated! # # mime::parseaddress takes a string containing one or more 822-style | > | | | | 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 | regsub -all -nocase {=([a-f0-9][a-f0-9])} $string {\\u00\1} string # process \u unicode mapped chars return [subst -novariables -nocommands $string] } # ::mime::parseaddress -- # # This was originally written circa 1982 in C. we're still using it # because it recognizes virtually every buggy address syntax ever # generated! # # mime::parseaddress takes a string containing one or more 822-style # address specifications and returns a list of dictionaries, for each # address specified in the argument. # # Each dictionary contains these properties: # # property value # ======== ===== # address local@domain # comment 822-style comment # domain the domain part (rhs) # error non-empty on a parse error |
︙ | ︙ | |||
2593 2594 2595 2596 2597 2598 2599 | # # Note that one or more of these properties may be empty. # # Arguments: # string The address string to parse # # Results: | | | < < < < > > > > > > > > > > > > > | < < | > | | | | < > | > > | 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 | # # Note that one or more of these properties may be empty. # # Arguments: # string The address string to parse # # Results: # Returns a list of dictionaries, one element for each address # specified in the argument. proc ::mime::parseaddress {string args} { variable mime set token [namespace current]::[incr mime(uid)] # FRINK: nocheck upvar 0 $token state if {[llength $args]} { set string2 [lindex $args end] set args [list $string {*}[lrange $args 0 end-1]] set string $string2 } dict for {opt val} $args { switch $opt { hostname { set state(default_host) $val } } } catch {mime::parseaddressaux $token $string} result copts foreach name [array names state] { unset state($name) } # FRINK: nocheck catch {unset $token} return -options $copts $result } # ::mime::parseaddressaux -- # # This was originally written circa 1982 in C. we're still using it # because it recognizes virtually every buggy address syntax ever # generated! # # mime::parseaddressaux does the actually parsing for mime::parseaddress # # Each dictionary contains these properties: # # property value # ======== ===== # address local@domain # comment 822-style comment # domain the domain part (rhs) # error non-empty on a parse error # group this address begins a group # friendly user-friendly rendering # local the local part (lhs) # memberP this address belongs to a group # phrase the phrase part # proper 822-style address specification # route 822-style route specification (obsolete) # # Note that one or more of these properties may be empty. # # Arguments: # token The MIME token to work from. # string The address string to parse # # Results: # Returns a list of dictionaries, one for each address specified in the # argument. proc ::mime::parseaddressaux {token string} { # FRINK: nocheck upvar 0 $token state variable addrtokenL variable addrlexemeL set state(input) $string set state(glevel) 0 set state(buffer) {} set state(lastC) LX_END set state(tokenL) $addrtokenL set state(lexemeL) $addrlexemeL set result {} while {[addr_next $token]} { if {[set tail $state(domain)] ne {}} { set tail @$state(domain) } else { if {![info exists state(default_host)]} { set state(default_host) [info hostname] } set tail @$state(default_host) } if {[set address $state(local)] ne {}} { #TODO: this path is not covered by tests append address $tail } if {$state(phrase) ne {}} { |
︙ | ︙ | |||
2702 2703 2704 2705 2706 2707 2708 | if {[set friendly $state(phrase)] eq {}} { #TODO: this path is not covered by tests if {[set note $state(comment)] ne {}} { if {[string first ( $note] == 0} { set note [string trimleft [string range $note 1 end]] } | > | | > | > | > | > > | > | > | 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 | if {[set friendly $state(phrase)] eq {}} { #TODO: this path is not covered by tests if {[set note $state(comment)] ne {}} { if {[string first ( $note] == 0} { set note [string trimleft [string range $note 1 end]] } if { [string last ) $note] == [set len [expr {[string length $note] - 1}]] } { set note [string range $note 0 [expr {$len - 1}]] } set friendly $note } if { $friendly eq {} && [set mbox $state(local)] ne {} } { #TODO: this path is not covered by tests set mbox [string trim $mbox \"] if {[string first / $mbox] != 0} { set friendly $mbox } elseif {[set friendly [addr_x400 $mbox PN]] ne {}} { } elseif { [set friendly [addr_x400 $mbox S]] ne {} && [set g [addr_x400 $mbox G]] ne {} } { set friendly "$g $friendly" } if {$friendly eq {}} { set friendly $mbox } } |
︙ | ︙ | |||
2743 2744 2745 2746 2747 2748 2749 | memberP $state(memberP) \ phrase $state(phrase) \ proper $proper \ route $state(route)] } | > | | | | | | > > | < < | | | | | | | < < | < > < | | 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 | memberP $state(memberP) \ phrase $state(phrase) \ proper $proper \ route $state(route)] } unset {*}{ state(input) state(glevel) state(buffer) state(lastC) state(tokenL) state(lexemeL) } return $result } # ::mime::addr_next -- # # Locate the next address in a mime token. # # Arguments: # token The MIME token to work from. # # Results: # Returns 1 if there is another address, and 0 if there is not. proc ::mime::addr_next token { # FRINK: nocheck upvar 0 $token state set nocomplain [package vsatisfies [package provide Tcl] 8.4] foreach prop {comment domain error group local memberP phrase route} { if {$nocomplain} { unset -nocomplain state($prop) } else { catch {unset state($prop)} } } switch [set code [catch {mime::addr_specification $token} result copts]] { 0 { if {!$result} { return 0 } switch $state(lastC) { LX_COMMA - LX_END { } default { # catch trailing comments... set lookahead $state(input) parselexeme $token set state(input) $lookahead } } } 7 { set state(error) $result while 1 { switch $state(lastC) { LX_COMMA - LX_END { break } default { parselexeme $token } } } } default { return -options $copts $result } } foreach prop {comment domain error group local memberP phrase route} { if {![info exists state($prop)]} { set state($prop) {} } } return 1 } # ::mime::addr_specification -- # # Uses lookahead parsing to determine whether there is another # valid e-mail address or not. Throws errors if unrecognized # or invalid e-mail address syntax is used. # # Arguments: # token The MIME token to work from. # # Results: # Returns 1 if there is another address, and 0 if there is not. proc ::mime::addr_specification {token} { # FRINK: nocheck upvar 0 $token state set lookahead $state(input) switch [parselexeme $token] { LX_ATOM - LX_QSTRING { set state(phrase) $state(buffer) } LX_SEMICOLON { |
︙ | ︙ | |||
2885 2886 2887 2888 2889 2890 2891 | LX_ATSIGN { set state(input) $lookahead return [addr_routeaddr $token 0] } default { | | | | | | 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 | LX_ATSIGN { set state(input) $lookahead return [addr_routeaddr $token 0] } default { return -code 7 [ format "unexpected character at beginning (found %s)" \ $state(buffer)] } } switch [parselexeme $token] { LX_ATOM - LX_QSTRING { append state(phrase) " " $state(buffer) return [addr_phrase $token] } |
︙ | ︙ | |||
2929 2930 2931 2932 2933 2934 2935 | LX_SEMICOLON - LX_COMMA - LX_END { set state(memberP) $state(glevel) | > | > | > > < | | 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 | LX_SEMICOLON - LX_COMMA - LX_END { set state(memberP) $state(glevel) if { $state(lastC) eq "LX_SEMICOLON" && ([incr state(glevel) -1] < 0) } { #TODO: this path is not covered by tests return -code 7 "extraneous semi-colon" } set state(local) $state(phrase) unset state(phrase) } default { return -code 7 [ format "expecting mailbox (found %s)" $state(buffer)] } } return 1 } # ::mime::addr_routeaddr -- # # Parses the domain portion of an e-mail address. Finds the '@' # sign and then calls mime::addr_route to verify the domain. # # Arguments: # token The MIME token to work from. # # Results: # Returns 1 if there is another address, and 0 if there is not. proc ::mime::addr_routeaddr {token {checkP 1}} { # FRINK: nocheck upvar 0 $token state set lookahead $state(input) if {[parselexeme $token] eq "LX_ATSIGN"} { #TODO: this path is not covered by tests mime::addr_route $token } else { set state(input) $lookahead } mime::addr_local $token switch $state(lastC) { LX_ATSIGN { mime::addr_domain $token } LX_SEMICOLON - LX_RBRACKET |
︙ | ︙ | |||
3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 | if {($checkP) && ($state(lastC) ne "LX_RBRACKET")} { return -code 7 [ format "expecting right-bracket (found %s)" $state(buffer)] } return 1 } # ::mime::addr_route -- # # Attempts to parse the portion of the e-mail address after the @. # Tries to verify that the domain definition has a valid form. # # Arguments: # token The MIME token to work from. # # Results: # Returns nothing if successful, and throws an error if invalid # syntax is found. proc ::mime::addr_route {token} { # FRINK: nocheck | > < | | | | | | 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 | if {($checkP) && ($state(lastC) ne "LX_RBRACKET")} { return -code 7 [ format "expecting right-bracket (found %s)" $state(buffer)] } return 1 } # ::mime::addr_route -- # # Attempts to parse the portion of the e-mail address after the @. # Tries to verify that the domain definition has a valid form. # # Arguments: # token The MIME token to work from. # # Results: # Returns nothing if successful, and throws an error if invalid # syntax is found. proc ::mime::addr_route {token} { # FRINK: nocheck upvar 0 $token state set state(route) @ while 1 { switch [parselexeme $token] { LX_ATOM - LX_DLITERAL { append state(route) $state(buffer) } default { return -code 7 \ [format "expecting sub-route in route-part (found %s)" \ $state(buffer)] } } switch [parselexeme $token] { LX_COMMA { append state(route) $state(buffer) while 1 { switch [parselexeme $token] { LX_COMMA { } LX_ATSIGN { append state(route) $state(buffer) break } |
︙ | ︙ | |||
3071 3072 3073 3074 3075 3076 3077 | LX_COLON { append state(route) $state(buffer) return } default { | | | | > | < | | | | | | > < | | | > < | | | | | | > < | | | | > < | | | > | 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 | LX_COLON { append state(route) $state(buffer) return } default { return -code 7 [ format "expecting colon to terminate route (found %s)" \ $state(buffer)] } } } } # ::mime::addr_domain -- # # Attempts to parse the portion of the e-mail address after the @. # Tries to verify that the domain definition has a valid form. # # Arguments: # token The MIME token to work from. # # Results: # Returns nothing if successful, and throws an error if invalid # syntax is found. proc ::mime::addr_domain token { # FRINK: nocheck upvar 0 $token state while 1 { switch [parselexeme $token] { LX_ATOM - LX_DLITERAL { append state(domain) $state(buffer) } default { return -code 7 [ format "expecting sub-domain in domain-part (found %s)" \ $state(buffer)] } } switch [parselexeme $token] { LX_DOT { append state(domain) $state(buffer) } LX_ATSIGN { append state(local) % $state(domain) unset state(domain) } default { return } } } } # ::mime::addr_local -- # # # Arguments: # token The MIME token to work from. # # Results: # Returns nothing if successful, and throws an error if invalid # syntax is found. proc ::mime::addr_local {token} { # FRINK: nocheck upvar 0 $token state set state(memberP) $state(glevel) while 1 { switch [parselexeme $token] { LX_ATOM - LX_QSTRING { append state(local) $state(buffer) } default { return -code 7 \ [format "expecting mailbox in local-part (found %s)" \ $state(buffer)] } } switch [parselexeme $token] { LX_DOT { append state(local) $state(buffer) } default { return } } } } # ::mime::addr_phrase -- # # # Arguments: # token The MIME token to work from. # # Results: # Returns nothing if successful, and throws an error if invalid # syntax is found. proc ::mime::addr_phrase {token} { # FRINK: nocheck upvar 0 $token state while 1 { switch [parselexeme $token] { LX_ATOM - LX_QSTRING { append state(phrase) " " $state(buffer) } default { break } } } switch $state(lastC) { LX_LBRACKET { return [addr_routeaddr $token] } LX_COLON { return [addr_group $token] } LX_DOT { append state(phrase) $state(buffer) return [addr_phrase $token] } default { return -code 7 [ format "found phrase instead of mailbox (%s%s)" \ $state(phrase) $state(buffer)] } } } # ::mime::addr_group -- # # # Arguments: # token The MIME token to work from. # # Results: # Returns nothing if successful, and throws an error if invalid # syntax is found. proc ::mime::addr_group {token} { # FRINK: nocheck upvar 0 $token state if {[incr state(glevel)] > 1} { return -code 7 [ format "nested groups not allowed (found %s)" $state(phrase)] } set state(group) $state(phrase) unset state(phrase) set lookahead $state(input) while 1 { switch [parselexeme $token] { LX_SEMICOLON - LX_END { set state(glevel) 0 return 1 } LX_COMMA { } default { set state(input) $lookahead return [addr_specification $token] } } } } # ::mime::addr_end -- # # # Arguments: # token The MIME token to work from. # # Results: # Returns nothing if successful, and throws an error if invalid # syntax is found. proc ::mime::addr_end {token} { # FRINK: nocheck upvar 0 $token state switch $state(lastC) { LX_SEMICOLON { if {[incr state(glevel) -1] < 0} { return -code 7 "extraneous semi-colon" } } LX_COMMA - LX_END { } default { return -code 7 [ format "junk after local@domain (found %s)" $state(buffer)] } } } # ::mime::addr_x400 -- # # # Arguments: # token The MIME token to work from. # |
︙ | ︙ | |||
3325 3326 3327 3328 3329 3330 3331 | if {[set x [string first / $mbox]] > 0} { set mbox [string range $mbox 0 [expr {$x - 1}]] } return [string trim $mbox \"] } | > | | | 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 | if {[set x [string first / $mbox]] > 0} { set mbox [string range $mbox 0 [expr {$x - 1}]] } return [string trim $mbox \"] } # ::mime::datetime -- # # Fortunately the clock command in the Tcl 8.x core does all the heavy # lifting for us (except for timezone calculations). # # mime::datetime takes a string containing an 822-style date-time # specification and returns the specified property. # # The list of properties and their ranges are: # # property range # ======== ===== # clock raw result of "clock scan" |
︙ | ︙ | |||
3377 3378 3379 3380 3381 3382 3383 | variable MONTHS_SHORT [list {} \ Jan Feb Mar Apr May Jun \ Jul Aug Sep Oct Nov Dec] variable MONTHS_LONG [list {} \ January February March April May June July \ August Sepember October November December] } | | | > | | 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 | variable MONTHS_SHORT [list {} \ Jan Feb Mar Apr May Jun \ Jul Aug Sep Oct Nov Dec] variable MONTHS_LONG [list {} \ January February March April May June July \ August Sepember October November December] } proc ::mime::datetime {value property} { if {$value eq "-now"} { set clock [clock seconds] } elseif {[regexp {^(.*) ([+-])([0-9][0-9])([0-9][0-9])$} $value \ -> value zone_sign zone_hour zone_min] } { set clock [clock scan $value -gmt 1] if {[info exists zone_min]} { set zone_min [scan $zone_min %d] set zone_hour [scan $zone_hour %d] set zone [expr {60 * ($zone_min + 60 * $zone_hour)}] if {$zone_sign eq "+"} { set zone -$zone } incr clock $zone } } else { set clock [clock scan $value] } switch $property { clock { return $clock } hour { set value [clock format $clock -format %H] } |
︙ | ︙ | |||
3430 3431 3432 3433 3434 3435 3436 | mon { set value [clock format $clock -format %m] } month { variable MONTHS_SHORT | | | | < | | | | | 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 | mon { set value [clock format $clock -format %m] } month { variable MONTHS_SHORT return [lindex $MONTHS_SHORT [ scan [clock format $clock -format %m] %d]] } proper { set gmt [clock format $clock -format "%Y-%m-%d %H:%M:%S" -gmt true] if {[set diff [expr {($clock-[clock scan $gmt]) / 60}]] < 0} { set s - set diff [expr {-($diff)}] } else { set s + } set zone [format %s%02d%02d $s [ expr {$diff / 60}] [expr {$diff % 60}]] variable WDAYS_SHORT set wday [lindex $WDAYS_SHORT [clock format $clock -format %w]] variable MONTHS_SHORT set mon [lindex $MONTHS_SHORT [ scan [clock format $clock -format %m] %d]] return [ clock format $clock -format "$wday, %d $mon %Y %H:%M:%S $zone"] } rclock { #TODO: these paths are not covered by tests if {$value eq "-now"} { return 0 } else { |
︙ | ︙ | |||
3492 3493 3494 3495 3496 3497 3498 | zone { set value [string trim [string map [list \t { }] $value]] if {[set x [string last { } $value]] < 0} { return 0 } set value [string range $value [expr {$x + 1}] end] | | > | > | > | > | > | > | 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 | zone { set value [string trim [string map [list \t { }] $value]] if {[set x [string last { } $value]] < 0} { return 0 } set value [string range $value [expr {$x + 1}] end] switch [set s [string index $value 0]] { + - - { if {$s eq "+"} { #TODO: This path is not covered by tests set s {} } set value [string trim [string range $value 1 end]] if {( [string length $value] != 4) || [scan $value %2d%2d h m] != 2 || $h > 12 || $m > 59 || ($h == 12 && $m > 0) } { error "malformed timezone-specification: $value" } set value $s[expr {$h * 60 + $m}] } default { set value [string toupper $value] |
︙ | ︙ | |||
3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 | if {[set value [string trimleft $value 0]] eq {}} { #TODO: this path is not covered by tests set value 0 } return $value } # ::mime::uniqueID -- # # Used to generate a 'globally unique identifier' for the content-id. # The id is built from the pid, the current time, the hostname, and # a counter that is incremented each time a message is sent. # # Arguments: # # Results: # Returns the a string that contains the globally unique identifier # that should be used for the Content-ID of an e-mail message. proc ::mime::uniqueID {} { | > | > > | < | | < | 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 | if {[set value [string trimleft $value 0]] eq {}} { #TODO: this path is not covered by tests set value 0 } return $value } # ::mime::uniqueID -- # # Used to generate a 'globally unique identifier' for the content-id. # The id is built from the pid, the current time, the hostname, and # a counter that is incremented each time a message is sent. # # Arguments: # # Results: # Returns the a string that contains the globally unique identifier # that should be used for the Content-ID of an e-mail message. proc ::mime::uniqueID {} { set id [base64 -mode encode -- [ sha2::sha256 -bin [expr {rand()}][pid][clock clicks][array get state]]] return $id } # ::mime::parselexeme -- # # Used to implement a lookahead parser. # # Arguments: # token The MIME token to operate on. # # Results: # Returns the next token found by the parser. proc ::mime::parselexeme token { # FRINK: nocheck upvar 0 $token state set state(input) [string trimleft $state(input)] set state(buffer) {} if {$state(input) eq {}} { set state(buffer) end-of-input |
︙ | ︙ | |||
3597 3598 3599 3600 3601 3602 3603 | set noteP 0 set quoteP 0 while 1 { append state(buffer) $c #TODO: some of these paths are not covered by tests | | | 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 | set noteP 0 set quoteP 0 while 1 { append state(buffer) $c #TODO: some of these paths are not covered by tests switch $c/$quoteP { (/0 { incr noteP } \\/0 { set quoteP 1 } |
︙ | ︙ | |||
3637 3638 3639 3640 3641 3642 3643 | if {$c eq "\""} { set firstP 1 set quoteP 0 while 1 { append state(buffer) $c | | | 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 | if {$c eq "\""} { set firstP 1 set quoteP 0 while 1 { append state(buffer) $c switch $c/$quoteP { "\\/0" { set quoteP 1 } "\"/0" { if {!$firstP} { return [set state(lastC) LX_QSTRING] |
︙ | ︙ | |||
3668 3669 3670 3671 3672 3673 3674 | if {$c eq {[}} { set quoteP 0 while 1 { append state(buffer) $c | | | 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 | if {$c eq {[}} { set quoteP 0 while 1 { append state(buffer) $c switch $c/$quoteP { \\/0 { set quoteP 1 } ]/0 { return [set state(lastC) LX_DLITERAL] } |
︙ | ︙ | |||
3692 3693 3694 3695 3696 3697 3698 | } set state(input) [string range $state(input) 1 end] } } if {[set x [lsearch -exact $state(tokenL) $c]] >= 0} { append state(buffer) $c | < | | > | 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 | } set state(input) [string range $state(input) 1 end] } } if {[set x [lsearch -exact $state(tokenL) $c]] >= 0} { append state(buffer) $c return [set state(lastC) [lindex $state(lexemeL) $x]] } while 1 { append state(buffer) $c switch [set c [string index $state(input) 0]] { {} - " " - "\t" - "\n" { break } default { if {[lsearch -exact $state(tokenL) $c] >= 0} { break } } } set state(input) [string range $state(input) 1 end] } return [set state(lastC) LX_ATOM] } # ::mime::mapencoding -- # # mime::mapencodings maps tcl encodings onto the proper names for their # MIME charset type. This is only done for encodings whose charset types # were known. The remaining encodings return {} for now. # |
︙ | ︙ | |||
3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 | variable encodings if {[info exists encodings($enc)]} { return $encodings($enc) } return {} } # ::mime::reversemapencoding -- # # mime::reversemapencodings maps MIME charset types onto tcl encoding names. # Those that are unknown return {}. # # Arguments: | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 | variable encodings if {[info exists encodings($enc)]} { return $encodings($enc) } return {} } # ::mime::property -- # # mime::property returns the properties of a MIME part. # # The properties are: # # property value # ======== ===== # content the type/subtype describing the content # encoding the "Content-Transfer-Encoding" # params a list of "Content-Type" parameters # parts a list of tokens for the part's subordinates # size the approximate size of the content (unencoded) # # The "parts" property is present only if the MIME part has # subordinates. # # If mime::property is invoked with the name of a specific # property, then the corresponding value is returned; instead, if # -names is specified, a list of all properties is returned; # otherwise, a dictionary of properties is returned. # # Arguments: # token The MIME token to parse. # property One of 'content', 'encoding', 'params', 'parts', and # 'size'. Defaults to returning a dictionary of # properties. # # Results: # Returns the properties of a MIME part proc ::mime::property {token {property {}}} { # FRINK: nocheck upvar 0 $token state parsepart $token lassign [header get $token content-type] content params switch $property { {} { array set properties [list content $content \ encoding $state(encoding) \ params $params \ size [getsize $token]] if {[info exists state(parts)]} { set properties(parts) $state(parts) } return [array get properties] } -names { set names [list content encoding params] if {[info exists state(parts)]} { lappend names parts } lappend nams size return $names } content - params { return [set $property] } encoding { return $state($property) } parts { if {![info exists state(parts)]} { error [list not a multipart message] } return $state(parts) } size { return [getsize $token] } default { error [list {unknown property} $property] } } } # ::mime::reversemapencoding -- # # mime::reversemapencodings maps MIME charset types onto tcl encoding names. # Those that are unknown return {}. # # Arguments: |
︙ | ︙ | |||
3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 | set lmimeType [string tolower $mimeType] if {[info exists reversemap($lmimeType)]} { return $reversemap($lmimeType) } return {} } # ::mime::word_encode -- # # Word encodes strings as per RFC 2047. # # Arguments: # charset The character set to encode the message to. # method The encoding method (base64 or quoted-printable). | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 | set lmimeType [string tolower $mimeType] if {[info exists reversemap($lmimeType)]} { return $reversemap($lmimeType) } return {} } # ::mime::serialize -- # # Serializes a message to a value or a channel. # # Arguments: # token The MIME token to parse. # channel The channel to copy the message to. # # Results: # Returns nothing unless an error is thrown while the message # is being written to the channel. proc ::mime::serialize {token args} { dict for {arg val} $args { switch $arg { -chan { return [serialize_chan $token $val] } default { error [list {unknown option} $arg] } } } # FRINK: nocheck upvar 0 $token state set openP [info exists state(fd)] set code [catch {mime::serialize_value $token} result copts] if {!$openP && [info exists state(fd)]} { if {![info exists state(root)]} { catch {close $state(fd)} } unset state(fd) } return -options $copts $result } proc ::mime::serialize_chan {token channel} { # FRINK: nocheck upvar 0 $token state upvar 0 state(fd) fd parsepart $token set result {} foreach {mixed value} [header get $token] { puts $channel [header serialize $token $mixed {*}$value] } set converter {} set encoding {} if {$state(value) ne "parts"} { if {$state(canonicalP)} { if {[set encoding $state(encoding)] eq {}} { set encoding [encoding $token] } if {$encoding ne {}} { puts $channel "Content-Transfer-Encoding: $encoding" } switch $encoding { base64 - quoted-printable { set converter $encoding } 7bit - 8bit - binary - {} { # Bugfix for [#477088], also [#539952] # Go ahead } default { error "Can't handle content encoding \"$encoding\"" } } } } if {[info exists state(error)]} { unset state(error) } switch $state(value) { file { if {[info exists state(root)]} { set size $state(count) } else { # read until eof set size -1 } seek $fd $state(offset) start puts $channel {} while {$size != 0 && ![eof $fd]} { if {$size < 0 || $size > 32766} { set X [read $fd 32766] } else { set X [read $fd $size] } if {$size > 0} { set size [expr {$size - [string length $X]}] } if {$converter eq {}} { puts -nonewline $channel $X } else { puts -nonewline $channel [$converter -mode encode -- $X] } } } parts { lassign [header get $token content-type] content params set boundary [dict get $params boundary] switch -glob $content { message/* { puts $channel {} foreach part $state(parts) { mime::serialize_chan $part $channel break } } default { # Note RFC 2046: See serialize_value for details. # # The boundary delimiter MUST occur at the # beginning of a line, i.e., following a CRLF, and # the initial CRLF is considered to be attached to # the boundary delimiter line rather than part of # the preceding part. # # - The above means that the CRLF before $boundary # is needed per the RFC, and the parts must not # have a closing CRLF of their own. See Tcllib bug # 1213527, and patch 1254934 for the problems when # both file/string branches added CRLF after the # body parts. foreach part $state(parts) { puts $channel \n--$boundary mime::serialize_chan $part $channel } puts $channel \n--$boundary-- } } } string { if {[catch {fconfigure $channel -buffersize} blocksize]} { set blocksize 4096 } elseif {$blocksize < 512} { set blocksize 512 } set blocksize [expr {($blocksize / 4) * 3}] # [893516] fconfigure $channel -buffersize $blocksize puts $channel {} #TODO: tests don't cover these paths if {$converter eq {}} { puts -nonewline $channel $state(string) } else { puts -nonewline $channel [$converter -mode encode -- $state(string)] } } default { error "Unknown value \"$state(value)\"" } } flush $channel if {[info exists state(error)]} { error $state(error) } } proc ::mime::serialize_value token { set chan [tcl::chan::memchan] chan configure $chan -translation crlf serialize_chan $token $chan seek $chan 0 chan configure $chan -translation binary set res [read $chan] close $chan return $res } # ::mime::word_encode -- # # Word encodes strings as per RFC 2047. # # Arguments: # charset The character set to encode the message to. # method The encoding method (base64 or quoted-printable). |
︙ | ︙ | |||
3784 3785 3786 3787 3788 3789 3790 | # Returns a word encoded string. proc ::mime::word_encode {charset method string {args}} { variable encodings if {![info exists encodings($charset)]} { | | | > | | 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 | # Returns a word encoded string. proc ::mime::word_encode {charset method string {args}} { variable encodings if {![info exists encodings($charset)]} { error [list {unknown charset} $charset] } if {$encodings($charset) eq {}} { error [list {invalid charset} $charset] } if {$method ne "base64" && $method ne "quoted-printable"} { error [list {unknown method} $method {must be one of} \ {base64 quoted-printable}] } # default to encoded and a length that won't make the Subject header to long array set options [list -charset_encoded 1 -maxlength 66] array set options $args if {$options(-charset_encoded)} { |
︙ | ︙ | |||
3815 3816 3817 3818 3819 3820 3821 | return {} } set string_bytelength [string bytelength $unencoded_string] # the 7 is for =?, ?Q?, ?= delimiters of the encoded word set maxlength [expr {$options(-maxlength) - [string length $encodings($charset)] - 7}] | | > | | | > | | > | | | | | 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 | return {} } set string_bytelength [string bytelength $unencoded_string] # the 7 is for =?, ?Q?, ?= delimiters of the encoded word set maxlength [expr {$options(-maxlength) - [string length $encodings($charset)] - 7}] switch -exact $method { base64 { if {$maxlength < 4} { error [list maxlength $options(-maxlength) \ {too short for chosen charset and encoding}] } set count 0 set maxlength [expr {($maxlength / 4) * 3}] while {$count < $string_length} { set length 0 set enc_string {} while {$length < $maxlength && $count < $string_length} { set char [string range $unencoded_string $count $count] set enc_char [::encoding convertto $charset $char] if {$length + [string length $enc_char] > $maxlength} { set length $maxlength } else { append enc_string $enc_char incr count incr length [string length $enc_char] } } set encoded_word [string map [ list \n {}] [base64 -mode encode -- $enc_string]] append result "=?$encodings($charset)?B?$encoded_word?=\n " } # Trim off last "\n ", since the above code has the side-effect # of adding an extra "\n " to the encoded string. set result [string range $result 0 end-2] } quoted-printable { if {$maxlength < 1} { error [list maxlength $options(-maxlength) \ {too short for chosen charset and encoding}] } set count 0 while {$count < $string_length} { set length 0 set encoded_word {} while {$length < $maxlength && $count < $string_length} { set char [string range $unencoded_string $count $count] set enc_char [::encoding convertto $charset $char] set qp_enc_char [qp_encode $enc_char 1] set qp_enc_char_length [string length $qp_enc_char] if {$qp_enc_char_length > $maxlength} { error [list maxlength $options(-maxlength) \ {too short for chosen charset and encoding}] } if { $length + [string length $qp_enc_char] > $maxlength } { set length $maxlength } else { append encoded_word $qp_enc_char incr count incr length [string length $qp_enc_char] } } |
︙ | ︙ | |||
3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 | } default { error "Can't handle content encoding \"$method\"" } } return $result } # ::mime::word_decode -- # # Word decodes strings that have been word encoded as per RFC 2047. # # Arguments: # encoded The word encoded string to decode. # # Results: # Returns the string that has been decoded from the encoded message. proc ::mime::word_decode {encoded} { variable reversemap if {[regexp -- {=\?([^?]+)\?(.)\?([^?]*)\?=} $encoded \ | > | > | | > | 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 | } default { error "Can't handle content encoding \"$method\"" } } return $result } # ::mime::word_decode -- # # Word decodes strings that have been word encoded as per RFC 2047. # # Arguments: # encoded The word encoded string to decode. # # Results: # Returns the string that has been decoded from the encoded message. proc ::mime::word_decode {encoded} { variable reversemap if {[regexp -- {=\?([^?]+)\?(.)\?([^?]*)\?=} $encoded \ - charset method string] != 1 } { error "malformed word-encoded expression '$encoded'" } set enc [reversemapencoding $charset] if {$enc eq {}} { error "unknown charset '$charset'" } switch -exact $method { b - B { set method base64 } q - Q { set method quoted-printable } default { error "unknown method '$method', must be B or Q" } } switch -exact $method { base64 { set result [base64 -mode decode -- $string] } quoted-printable { set result [qp_decode $string 1] } {} { # Go ahead } default { error "Can't handle content encoding \"$method\"" } } return [list $enc $method $result] } # ::mime::field_decode -- # # Word decodes strings that have been word encoded as per RFC 2047 # and converts the string from the original encoding/charset to UTF. # # Arguments: |
︙ | ︙ | |||
3967 3968 3969 3970 3971 3972 3973 | # version with unencoded equivalents. # Sorry about the grotesque regexp. Most of it is sensible. One # notable fudge: the final $ is needed because of an apparent bug # in the regexp engine where the preceding .* otherwise becomes # non-greedy - perhaps because of the earlier ".*?", sigh. | | > > | > > > > > > > > > > > > > > > > > > > > | 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 | # version with unencoded equivalents. # Sorry about the grotesque regexp. Most of it is sensible. One # notable fudge: the final $ is needed because of an apparent bug # in the regexp engine where the preceding .* otherwise becomes # non-greedy - perhaps because of the earlier ".*?", sigh. while {[regexp {(.*?)(=\?(?:[^?]+)\?(?:.)\?(?:[^?]*)\?=)(.*)$} $field \ ignore prefix encoded field] } { # don't allow whitespace between encoded words per RFC 2047 if {{} ne $prefix} { if {![string is space $prefix]} { append result $prefix } } set decoded [word_decode $encoded] foreach {charset - string} $decoded break append result [::encoding convertfrom $charset $string] } append result $field return $result } namespace eval ::mime::header { ::apply [list {} { set saved [namespace eval [namespace parent] { namespace export }] namespace eval [namespace parent] { namespace export * } namespace import [namespace parent]::getTransferEncoding namespace import [namespace parent]::parselexeme namespace import [namespace parent]::reversemapencoding namespace import [namespace parent]::uniqueID namespace eval [namespace parent] [ list namespace export -clear {*}$saved ] } [namespace current]] } ## One-Shot Initialization ::apply {{} { variable encList variable encAliasList variable reversemap |
︙ | ︙ |
Changes to modules/mime/mime.test.
1 2 3 4 | # mime.test - Test suite for TclMIME -*- tcl -*- # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > | | > | > > > > > > > > > > > > > > > > | | | | < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > | | > | | | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | # mime.test - Test suite for TclMIME -*- tcl -*- # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # genere totes output for errors. No output means no errors were found. # # Copyright (c) 2000 by Ajuba Solutions # All rights reserved. # # RCS: @(#) $Id: mime.test,v 1.31 2012/02/23 17:35:17 andreas_kupries Exp $ # ------------------------------------------------------------------------- source [file join \ [file dirname [file dirname [file dirname [ file normalize [info script]/...]]]]/devtools/testutilities.tcl] testsNeedTcl 8.5 testsNeedTcltest 1.0- support { # This code loads md5x, i.e. md5 v2. Proper testing should do one # run using md5 v1, aka md5.tcl as well. use md5/md5x.tcl md5 use namespacex/namespacex.tcl namespacex } testing { useLocal mime.tcl mime } # ------------------------------------------------------------------------- namespace import mime::* # ------------------------------------------------------------------------- proc channamescmp names { expr {[llength $names] == [llength [chan names]]} } proc cleanly script { set ns [info cmdcount] namespace eval $ns { namespace path [namespace parent] } catch {namespace eval $ns $script} cres copts namespace delete $ns return -options $copts $cres } proc setup1 {} { uplevel 1 { set channames [chan names] } } proc with.chan {name args} { set body [lindex $args end] set args [lrange $args 0 end-1] set chan [open $name] uplevel 1 [list set tok [::mime::initialize {*}$args -chan $chan]] uplevel 1 $body } proc with.file {name args} { set body [lindex $args end] set args [lrange $args 0 end-1] uplevel 1 [list set tok [::mime::initialize {*}$args -file $name]] uplevel 1 $body } proc main {} { variable encoded variable name variable n test mime-1.1 {initialize with no args} {cleanly { catch {initialize} res subst $res }} {{specify exactly one of} {-file -parts -string}} test mime-2.1 {Generate a MIME message} {cleanly { set tok [initialize -canonical Text/plain -string {jack and jill}] set msg [mime::serialize $tok] # The generated message is predictable except for the Content-ID regexp "MIME-Version: 1.0\r Content-ID: \[^\n]+\r Content-Type: text/plain\r \r jack and jill" $msg }} 1 foreach name {file chan} { test mime-2.1.1.$name {Generate a MIME message} {cleanly { setup1 with.$name [makeFile {jack and jill} input.txt] -canonical Text/plain { set msg [mime::body $tok] mime::finalize $tok # The generated message is predictable except for the Content-ID lappend res $msg lappend res [channamescmp $channames] return $res } }} [list "jack and jill\n" 1] } test mime-2.2 {Generate a multi-part MIME message} {cleanly { set tok1 [initialize -canonical Text/plain -string {jack and jill}] set tok2 [initialize -canonical Text/plain -string james] set bigTok [mime::initialize -canonical Multipart/MyType \ -params [list MyParam foo boundary bndry] \ -headers [list Content-Description {Test Multipart}] \ -parts [list $tok1 $tok2]] set msg [mime::serialize $bigTok] # The generated message is predictable except for the Content-ID list [regexp "MIME-Version: 1.0\r Content-ID: \[^\n]+\r Content-Type: multipart/mytype\r \t; \[^\n]+\r \t; \[^\n]+\r Content-Description: Test Multipart\r \r --bndry\r MIME-Version: 1.0\r Content-ID: \[^\n]+\r Content-Type: text/plain\r \r jack and jill\r --bndry\r MIME-Version: 1.0\r Content-ID: \[^\n]+\r Content-Type: text/plain\r \r james\r --bndry--\r " $msg] [regexp boundary=bndry $msg] [regexp myparam=foo $msg] }} {1 1 1} test mime-2.3 {Generate a multi-part MIME message} {cleanly { set tok1 [initialize -canonical Text/plain -string {jack and jill}] set tok2 [initialize -canonical Text/plain -string james] set bigTok [mime::initialize \ -params [list MyParam foo boundary bndry] \ -headers [list Content-Description {Test Multipart}] \ -parts [list $tok1 $tok2]] set msg [mime::serialize $bigTok] # The generated message is predictable except for the Content-ID list [regexp "MIME-Version: 1.0\r Content-ID: \[^\n]+\r Content-Type: multipart/mixed\r ; \[^\n]+\r ; \[^\n]+\r Content-Description: Test Multipart\r \r --bndry\r MIME-Version: 1.0\r Content-ID: \[^\n]+\r Content-Type: text/plain\r \r jack and jill\r --bndry\r MIME-Version: 1.0\r Content-ID: \[^\n]+\r Content-Type: text/plain\r \r james\r --bndry--\r " $msg] [regexp boundary=bndry $msg] [regexp myparam=foo $msg] }} {1 1 1} test mime-3.1 {Parse a MIME message} {cleanly { set msg {MIME-Version: 1.0 Content-Type: Text/plain I'm the message.} set tok [mime::initialize -string $msg] mime::body $tok }} {I'm the message.} test mime-3.2 {Parse a multi-part MIME message} {cleanly { set msg {MIME-Version: 1.0 Content-Type: Multipart/foo; boundary="bar" --bar MIME-Version: 1.0 Content-Type: Text/plain |
︙ | ︙ | |||
110 111 112 113 114 115 116 | Content-Type: Text/plain part3 --bar-- } set tok [mime::initialize -string $msg] | | | | | > | > | > | | | | > | | > > | | | | | > > | < | < | | | | | | > | | < | | | | | | | > | | > > > > | | | > | | | > | | | > | | | > | | | > | | > | | > | | > | | | | | > | > > > > > > | > | > > > > > > | | > | | | > | | | > | | > > > | | > > | > | > > | > > | > | | | > > | | | | < | | > > > > > > > > > > > > > | | | > | | | | | > | | | | | | | | | | | | | | > | | | > | | | > | | | > | | | > | | | > | | | > | | | > | | | > | | > | | | | > | | | > | | | | | | > | | | > | | > | | > | | | | | | | | | | | | | | | | | | | | < > | | | | | > | | | > | | | > | | | | < | | | | | | | | | | | > > | | > | | | | | | | | 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 | Content-Type: Text/plain part3 --bar-- } set tok [mime::initialize -string $msg] set partToks [mime::property $tok parts] set res {} foreach childTok $partToks { lappend res [mime::body $childTok] } set res }} {part1 part2 part3} test mime-3.3 {Try to parse a totally invalid message} { set token [mime::initialize -string blah] catch {mime::header get $token} err0 set err0 } {{improper line in header} blah} test mime-3.4 {Try to parse a MIME message with an invalid version} {cleanly { set msg1 {MIME-Version: 2.0 Content-Type: text/plain msg1} set tok [mime::initialize -string $msg1] catch {mime::body $tok} err1 catch {mime::serialize $tok} err1a list $err1 $err1a }} "msg1 {MIME-Version: 2.0\r Content-Type: text/plain\r \r msg1}" test mime-3.5 {Try to parse a MIME message with no newline between headers and data} {cleanly { set msg2 {MIME-Version: 1.0 Content-Type: foobar data without newline} set token [mime::initialize -string $msg2] catch {mime::header get $token} err2 set err2 }} {expecting type/subtype found foobar} test mime-3.6 {Try to parse a MIME message with no MIME version and generate a new message from it} {cleanly { # No MIME version set msg3 {Content-Type: text/plain foo} set tok [mime::initialize -string $msg3] catch {mime::body $tok} err3 catch {mime::serialize $tok} err3a list $err3 $err3a }} "foo {MIME-Version: 1.0\r Content-Type: text/plain\r \r foo}" foreach name {file chan} { test mime-3.7.$name {Test mime with a bad email [SF Bug 631314 ]} {cleanly { with.$name $tcltest::testsDirectory/badmail1.txt { set res {} set ctok [lindex [mime::property $tok parts] 0] lappend res [dictsort [mime::property $tok]] lappend res [dictsort [mime::property $ctok]] mime::finalize $tok string map [list $ctok CHILD] $res } }} {{content multipart/mixed encoding {} params {boundary ----------CSFNU9QKPGZL79} parts CHILD size 0} {content application/octet-stream encoding {} params {} size 0}} test mime-3.8 {Test mime with another bad email [SF Bug 631314 ]} {cleanly { with.$name $tcltest::testsDirectory/badmail2.txt { set res {} set ctok [lindex [mime::property $tok parts] 0] lappend res [dictsort [mime::property $tok]] lappend res [dictsort [mime::property $ctok]] mime::finalize $tok string map [list $ctok CHILD] $res } }} {{content multipart/related encoding {} params {boundary ----=_NextPart_000_0000_2CBA2CBA.150C56D2} parts CHILD size 659} {content application/octet-stream encoding base64 params {} size 659}} } test mime-3.9 {Parse a MIME message with a charset encoded body and use [body] -decode to get it back} {cleanly { set msg {MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Fran\xE7ois } set tok [mime::initialize -string $msg] mime::body $tok -decode }} {Fran\xE7ois } test mime-3.10 {Parse a MIME message with a charset encoded body and use [body] -decode to get it back (example from encoding man page)} {cleanly { set msg {MIME-Version: 1.0 Content-Type: text/plain; charset=EUC-JP Content-Transfer-Encoding: quoted-printable =A4=CF} set tok [mime::initialize -string $msg] mime::body $tok -decode }} \u306F test mime-3.11 {Parse a MIME message without a charset encoded body and use [body] -decode to get it back} {cleanly { set msg {MIME-Version: 1.0 Content-Type: text/plain Content-Transfer-Encoding: quoted-printable A plain text message.} set tok [mime::initialize -string $msg] mime::body $tok -decode }} {A plain text message.} test mime-3.12 {Parse a MIME message with a charset encoded body in an unrecognised charset and use [body] -decode to attempt to get it back} {cleanly { set msg {MIME-Version: 1.0 Content-Type: text/plain; charset=SCRIBBLE Content-Transfer-Encoding: quoted-printable This is a message in the scribble charset that tcl does not recognise.} set tok [mime::initialize -string $msg] catch {mime::body $tok -decode} errmsg set errmsg }} {{-decode cannot reversemap charset} SCRIBBLE} test mime-3.13 {Parse a MIME message with a charset encoded body in an unrecognised charset but don't use -decode so we get it back raw} {cleanly { set msg {MIME-Version: 1.0 Content-Type: text/plain; charset=SCRIBBLE Content-Transfer-Encoding: quoted-printable This is a message in the scribble charset that tcl does not recognise.} set tok [mime::initialize -string $msg] mime::body $tok }} {This is a message in the scribble charset that tcl does not recognise.} test mime-4.1 {Test qp_encode with a > 76 character string containing special chars.} {cleanly { set str1 "foo!\"\t barbaz \$ ` \{ # jack and jill went up a hill to fetch a pail of water. Jack fell down and said !\"\#\$@\[\\\]^`\{\|\}\~ \nJill said, \"Oh my\"" mime::qp_encode $str1 }} "foo=21=22\t barbaz =24 =60 =7B =23 jack and jill went up a hill to fetch a=\n pail of water. Jack fell down and said =21=22=23=24=40=5B=5C=5D=5E=60=7B=\n=7C=7D=7E =20\nJill said, =22Oh my=22" test mime-4.2 {Check that encode/decode yields original string} {cleanly { set str1 "foo!\"\t barbaz \$ ` \{ # jack and jill went up a hill to fetch a pail of water. Jack fell down and said !\"\#\$@\[\\\]^`\{\|\}\~ \nJill said, \"Oh my\" " set enc [mime::qp_encode $str1] set dec [mime::qp_decode $enc] string equal $dec $str1 }} 1 test mime-4.3 {mime::decode data that might come from an MUA} {cleanly { set enc "I'm the =22 message =\nwith some new lines= \n but with some extra space, too. " mime::qp_decode $enc }} "I'm the \" message with some new lines but with some extra space, too." test mime-4.4 {Test qp_encode with non-US_ASCCI characters.} {cleanly { set str1 "Test de caractères accentués : â î é ç et quelques contrôles \"\[|\]()\"" mime::qp_encode $str1 }} "Test de caract=E8res accentu=E9s : =E2 =EE =E9 =E7 et quelques contr=F4le=\ns =22=5B=7C=5D()=22" test mime-4.5 {Test qp_encode with softbreak} {cleanly { set str1 [string repeat abc 40] mime::qp_encode $str1 }} "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabca= bcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc" test mime-4.6 {Test qp_encode with softbreak} {cleanly { set str1 [string repeat abc 40] mime::qp_encode $str1 0 1 }} [string repeat abc 40] test mime-4.7 {Test qp_encode/decode in encoded_word mode} {cleanly { set enc [mime::qp_encode {jack and jill went up the hill} 1] mime::qp_decode $enc 1 }} {jack and jill went up the hill} test mime-4.8 {Test qp_encode in encoded_word mode with equal signs} {cleanly { mime::qp_encode 1and1=2 1 }} 1and1=3D2 test mime-4.9 {Test qp_encode in encoded_word mode with tabs and spaces} {cleanly { mime::qp_encode "1 and 1 =\t2" 1 }} 1_and_1_=3D=092 test mime-4.10 {Test qp_encode in encoded_word mode with underscores} {cleanly { mime::qp_encode 2003_06_30 1 }} 2003=5F06=5F30 test mime-4.11 {Test qp_encode in encoded_word mode with underscores and spaces} {cleanly { mime::qp_encode {2003_06_30 is 30 June 2003} 1 }} 2003=5F06=5F30_is_30_June_2003 test mime-4.12 {Test qp_encode in encoded_word mode with question marks} {cleanly { mime::qp_encode {How long is a piece of string ?} 1 }} How_long_is_a_piece_of_string_=3F test mime-4.13 {Test qp_encode in no_softbreak mode} {cleanly { mime::qp_encode {This is a very long string into which we do not want inserted softbreaks as we want one very long line returned even though that's probably not how we whould be doing it (see RFC2047) but we don't want to break backward compatibility} 0 1 }} {This is a very long string into which we do not want inserted softbreaks as we want one very long line returned even though that's probably not how we whould be doing it (see RFC2047) but we don't want to break backward compatibility} test mime-5.1 {Test word_encode with quoted-printable method} {cleanly { mime::word_encode iso8859-1 quoted-printable {Test de contrôle effectué} }} =?ISO-8859-1?Q?Test_de_contr=F4le_effectu=E9?= test mime-5.2 {Test word_encode with base64 method} {cleanly { mime::word_encode iso8859-1 base64 {Test de contrôle effectué} }} =?ISO-8859-1?B?VGVzdCBkZSBjb250cvRsZSBlZmZlY3R16Q==?= test mime-5.3 {Test encode+decode with quoted-printable method} {cleanly { set enc [mime::word_encode iso8859-1 quoted-printable {Test de contrôle effectué}] mime::word_decode $enc }} {iso8859-1 quoted-printable {Test de contrôle effectué}} test mime-5.4 {Test encode+decode with base64 method} {cleanly { set enc [mime::word_encode iso8859-1 base64 {Test de contrôle effectué}] mime::word_decode $enc }} {iso8859-1 base64 {Test de contrôle effectué}} test mime-5.5 {Test decode with lowercase quoted-printable method} {cleanly { mime::word_decode =?ISO-8859-1?q?Test_lowercase_q?= }} {iso8859-1 quoted-printable {Test lowercase q}} test mime-5.6 {Test decode with lowercase base64 method} {cleanly { mime::word_decode =?ISO-8859-1?b?VGVzdCBsb3dlcmNhc2UgYg==?= }} {iso8859-1 base64 {Test lowercase b}} test mime-5.7 {Test word_encode with quoted-printable method across encoded word boundaries} {cleanly { mime::word_encode iso8859-1 quoted-printable {Test de contrôle effectué} -maxlength 31 }} "=?ISO-8859-1?Q?Test_de_contr?= =?ISO-8859-1?Q?=F4le_effectu?= =?ISO-8859-1?Q?=E9?=" test mime-5.8 {Test word_encode with quoted-printable method across encoded word boundaries} {cleanly { mime::word_encode iso8859-1 quoted-printable {Test de contrôle effectué} -maxlength 32 }} "=?ISO-8859-1?Q?Test_de_contr?= =?ISO-8859-1?Q?=F4le_effectu?= =?ISO-8859-1?Q?=E9?=" test mime-5.9 {Test word_encode with quoted-printable method and multibyte character} {cleanly { mime::word_encode euc-jp quoted-printable "Following me is a multibyte character \xA4\xCF" }} =?EUC-JP?Q?Following_me_is_a_multibyte_character_=A4=CF?= set n 10 while {$n < 14} { test mime-5.$n {Test word_encode with quoted-printable method and multibyte character across encoded word boundary} {cleanly { mime::word_encode euc-jp quoted-printable "Following me is a multibyte character \xA4\xCF" -maxlength [expr 42 + $n] }} "=?EUC-JP?Q?Following_me_is_a_multibyte_character_?= =?EUC-JP?Q?=A4=CF?=" incr n } test mime-5.14 {Test word_encode with quoted-printable method and multibyte character (triple)} {cleanly { mime::word_encode utf-8 quoted-printable "Here is a triple byte encoded character \xE3\x81\xAF" }} =?UTF-8?Q?Here_is_a_triple_byte_encoded_character_=E3=81=AF?= set n 15 while {$n < 23} { test mime-5.$n {Test word_encode with quoted-printable method and triple byte character across encoded word boundary} {cleanly { mime::word_encode utf-8 quoted-printable "Here is a triple byte encoded character \xE3\x81\xAF" -maxlength [expr 38 + $n] }} "=?UTF-8?Q?Here_is_a_triple_byte_encoded_character_?= =?UTF-8?Q?=E3=81=AF?=" incr n } while {$n < 25} { test mime-5.$n {Test word_encode with quoted-printable method and triple byte character across encoded word boundary} {cleanly { mime::word_encode utf-8 quoted-printable "Here is a triple byte encoded character \xE3\x81\xAF" -maxlength [expr 38 + $n] }} =?UTF-8?Q?Here_is_a_triple_byte_encoded_character_=E3=81=AF?= incr n } while {$n < 29} { test mime-5.$n {Test word_encode with base64 method across encoded word boundaries} {cleanly { mime::word_encode euc-jp base64 "There is a multibyte character \xA4\xCF" -maxlength [expr 28 + $n] }} "=?EUC-JP?B?VGhlcmUgaXMgYSBtdWx0aWJ5dGUgY2hhcmFjdGVy?= =?EUC-JP?B?IKTP?=" incr n } while {$n < 33} { test mime-5.$n {Test word_encode with base64 method and triple byte character across encoded word boundary} {cleanly { mime::word_encode utf-8 base64 "Here is a multibyte character \xE3\x81\xAF" -maxlength [expr 23 + $n] }} "=?UTF-8?B?SGVyZSBpcyBhIG11bHRpYnl0ZSBjaGFyYWN0ZXIg?= =?UTF-8?B?44Gv?=" incr n } test mime-5.33 {Test word_encode with quoted-printable method and -maxlength set to same length as will the result} {cleanly { mime::word_encode iso8859-1 quoted-printable 123 -maxlength 20 }} =?ISO-8859-1?Q?123?= test mime-5.34 {Test word_encode with base64 method and -maxlength set to same length as will the result} {cleanly { mime::word_encode iso8859-1 base64 123 -maxlength 21 }} =?ISO-8859-1?B?MTIz?= test mime-5.35 {Test word_encode with quoted-printable method and non charset encoded string} {cleanly { mime::word_encode utf-8 quoted-printable \u306F -charset_encoded 0 }} =?UTF-8?Q?=E3=81=AF?= test mime-5.36 {Test word_encode with base64 method and non charset encoded string} {cleanly { mime::word_encode utf-8 base64 \u306F -charset_encoded 0 }} =?UTF-8?B?44Gv?= test mime-5.36 {Test word_encode with base64 method and one byte} {cleanly { mime::word_encode iso8859-1 base64 a }} =?ISO-8859-1?B?YQ==?= test mime-5.37 {Test word_encode with base64 method and two bytes} {cleanly { mime::word_encode euc-jp base64 \xA4\xCF }} =?EUC-JP?B?pM8=?= test mime-5.38 {Test word_encode with unknown charset} {cleanly { catch {mime::word_encode scribble quoted-printable {scribble is an unknown charset}} errmsg set errmsg }} {{unknown charset} scribble} test mime-5.39 {Test word_encode with invalid charset} {cleanly { catch {mime::word_encode unicode quoted-printable {unicode is not a valid charset}} errmsg set errmsg }} {{invalid charset} unicode} test mime-5.40 {Test word_encode with invalid method} {cleanly { catch {mime::word_encode iso8859-1 tea-leaf {tea-leaf is not a valid method}} errmsg set errmsg }} {{unknown method} tea-leaf {must be one of} {base64 quoted-printable}} test mime-5.41 {Test word_encode with maxlength to short for method quoted-printable} {cleanly { catch {mime::word_encode iso8859-1 quoted-printable 1 -maxlength 17} errmsg set errmsg }} {maxlength 17 {too short for chosen charset and encoding}} test mime-5.42 {Test word_encode with maxlength on the limit for quoted_printable and an unquoted character} {cleanly { catch {mime::word_encode iso8859-1 quoted-printable _ -maxlength 20} errmsg set errmsg }} =?ISO-8859-1?Q?=5F?= test mime-5.43 {Test word_encode with maxlength to short for method quoted_printable and a character to be quoted} {cleanly { catch {mime::word_encode iso8859-1 quoted-printable = -maxlength 18} errmsg set errmsg }} {maxlength 18 {too short for chosen charset and encoding}} test mime-5.44 {Test word_encode with maxlength to short for method quoted-printable and multibyte character} {cleanly { catch {mime::word_encode euc-jp quoted-printable \xA4\xCF -maxlength 17} errmsg set errmsg }} {maxlength 17 {too short for chosen charset and encoding}} test mime-5.45 {Test word_encode with maxlength to short for method base64} {cleanly { catch {mime::word_encode iso8859-1 base64 1 -maxlength 20} errmsg set errmsg }} {maxlength 20 {too short for chosen charset and encoding}} test mime-6.1 {Test field_decode (from RFC 2047, part 8)} {cleanly { mime::field_decode {=?US-ASCII?Q?Keith_Moore?= <[email protected]>} }} {Keith Moore <[email protected]>} test mime-6.2 {Test field_decode (from RFC 2047, part 8)} {cleanly { mime::field_decode {=?ISO-8859-1?Q?Patrik_F=E4ltstr=F6m?= <[email protected]>} }} {Patrik Fältström <[email protected]>} test mime-6.3 {Test field_decode (from RFC 2047, part 8)} {cleanly { mime::field_decode {=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=} }} {If you can read this you understand the example.} foreach {n encoded expected} { 4 (=?ISO-8859-1?Q?a?=) (a) 5 {(=?ISO-8859-1?Q?a?= b)} {(a b)} 6 {(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)} (ab) 7 {(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)} (ab) 8 "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)" (ab) 9 (=?ISO-8859-1?Q?a_b?=) {(a b)} 10 {(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=)} {(a b)} 11 {(=?ISO-8859-1?Q?a?=x=?ISO-8859-2?Q?_b?=)} {(ax b)} 12 {a b c} {a b c} 13 {} {} } { test mime-6.$n {Test field_decode (from RFC 2047, part 8)} {cleanly { mime::field_decode $encoded }} $expected ; # {} } foreach {bug n encoded expected} { 764702 1 {(=?utf-8?Q?H=C3=BCrz?=)} {(Hürz)} } { test mime-7.$n "Test field_decode (from SF Tcllib bug $bug)" {cleanly { mime::field_decode $encoded }} $expected ; # {} } test mime-8.1 {Test reversemapencoding+mapencoding with preferred name} {cleanly { set charset [mime::reversemapencoding US-ASCII] mime::mapencoding $charset }} US-ASCII test mime-8.2 {Test reversemapencoding+mapencoding with alias} {cleanly { set charset [mime::reversemapencoding UTF8] mime::mapencoding $charset }} UTF-8 foreach name {file chan} { test mime-9.0.$name {Test chunk handling of serialize and helpers} {cleanly { set in [makeFile [set data [string repeat [string repeat {123456789 } 10]\n 350]] input.txt] set mi [makeFile {} mime.txt] with.$name $in -canonical text/plain { set f [open $mi w] fconfigure $f -translation binary mime::serialize $tok -chan $f close $f with.$name $mi { set newdata [mime::body $tok] set res [string compare $data $newdata] removeFile input.txt removeFile mime.txt unset data newdata tok f in mi set res } } }} 0 } set ::env(TZ) UTC0 set epoch [clock scan 2000-01-01] foreach {n stamp date} { 1 86340 {Sat, 01 Jan 2000 23:59:00 +0000} 2 5176620 {Tue, 29 Feb 2000 21:57:00 +0000} 3 31610520 {Sun, 31 Dec 2000 20:42:00 +0000} 4 31708740 {Mon, 01 Jan 2001 23:59:00 +0000} 5 68248620 {Thu, 28 Feb 2002 21:57:00 +0000} 6 126218520 {Wed, 31 Dec 2003 20:42:00 +0000} } { test mime-10.$n "Test formatting dates (RFC 822)" { # To verify that clock scan gets the expected value. set stamp_test [expr {[mime::datetime $date clock] - $epoch}] # Parse and re-format should get us the original. set parsed_test [mime::datetime $date proper] list $stamp_test $parsed_test } [list $stamp $date] } test mime-11.0 {Bug 1825092} {cleanly { set in [makeFile {From [email protected] Sat Oct 20 17:58:49 2007 Return-Path: <[email protected]> Message-ID: <[email protected]> From: Somwhere <[email protected]> MIME-Version: 1.0 To: Here <[email protected]> Subject: test |
︙ | ︙ | |||
559 560 561 562 563 564 565 | name="a0036.dss" BGRzcwEAAQABAAAAYQAAAAAAAAAAAAAAAAAAACQAAAD+//7/+/8wNzA2MTYwODE1MjQwNzA2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ --------------090305080603000703000106-- } mail_part] set token [mime::initialize -file $in] | | | | | | < | | > > | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | name="a0036.dss" BGRzcwEAAQABAAAAYQAAAAAAAAAAAAAAAAAAACQAAAD+//7/+/8wNzA2MTYwODE1MjQwNzA2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ --------------090305080603000703000106-- } mail_part] set token [mime::initialize -file $in] set allparts [mime::property $token parts] set attachment [lindex $allparts 1] set out [makeFile {} mail_att] set ofh [open $out w] fconfigure $ofh -translation binary mime::serialize $attachment -chan $ofh close $ofh set data [viewFile $out] file delete $in $out set data }} {MIME-Version: 1.0 Content-Disposition: attachment ; filename=a0036.dss Content-Type: application/octet-stream ; name=a0036.dss Content-Transfer-Encoding: base64 BGRzcwEAAQABAAAAYQAAAAAAAAAAAAAAAAAAACQAAAD+//7/+/8wNzA2MTYwODE1MjQwNzA2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ} # ------------------------------------------------------------------------- test mime-12.0 {Bug 3483716} {cleanly { set token [mime::initialize -string {Content-Type: message/delivery-status; name="deliverystatus.txt" Content-Disposition: attachment; filename="deliverystatus.txt"; size=138; creation-date="Thu, 02 Feb 2012 13:50:05 GMT"; modification-date="Thu, 02 Feb 2012 13:50:05 GMT" Content-Description: deliverystatus.txt Content-Transfer-Encoding: base64 T3JpZ2luYWwtUmVjaXBpZW50OiA8L2ZheD1ibHViYkBndW1taS5ib290PgpBY3Rpb246IGZhaWxl ZApEaWFnbm9zdGljLUNvZGU6IHNtdHA7IDU1MCAjNS4xLjAgQWRkcmVzcyByZWplY3RlZC4KUmVt b3RlLU1UQTogNTMuMjQuMjgyLjE1MA== }] set parts [mime::property $token parts] lassign [mime::header get [lindex $parts end] Remote-MTA] result return $result }} 53.24.282.150 # ------------------------------------------------------------------------- test mime-13.0 {cleanly { issue a16b1095974e071d }} { set msg "MIME-Version: 1.0 Content-Type: text/plain\r \r so plain " set tok [mime::initialize -string $msg] mime::body $tok } "so plain\n" # ------------------------------------------------------------------------- test mime-14.0 {cleanly { hostname argument to parseaddress }} { set parsed [mime::parseaddress hostname fakedomain.fake {Here <h>}] list [llength $parsed] [lindex $parsed 0] } [list 1 [list address [email protected] comment {} domain {} error {} \ friendly Here group {} local h memberP 0 phrase Here \ proper {Here <[email protected]>} route {}]] test mime-14.1 {cleanly { special characters in local part }} { set parsed [mime::parseaddress hostname fakedomain.fake foo<>[email protected]] list [llength $parsed] [lindex $parsed 0] } [list 1 [list address {} comment {} domain {} \ error {expecting mailbox in local-part (found >)} friendly foo group {} \ local {} memberP 0 phrase foo proper {foo <>} route {}]] # ------------------------------------------------------------------------- test mime-15.0 {cleanly { a multipart/mixed message with an invalid body }} { set msg "MIME-Version: 1.0 Content-Type: multipart/mixed; boundary=\"something\"\r \r so plain " set tok [mime::initialize -string $msg] mime::header get $tok } [list MIME-Version {1.0 {}} Content-Type \ {multipart/mixed {boundary something}}] # ------------------------------------------------------------------------- test mime-16.0 {cleanly { }} { set msg "MIME-Version: 1.0 Content-Type: text/plain\r Content-Disposition: attachment ; param1=\"a parameter value\"; param2*1=\"another param\"; param2*2=\"eter value\" \r \r so plain " set tok [mime::initialize -string $msg] mime::header get $tok } [list MIME-Version {1.0 {}} Content-Type {text/plain {}} Content-Disposition [ list attachment [list param1 {a parameter value} \ param2 {another parameter value}]]] set char [encoding convertfrom utf-8 \xE3\x81\xAF] test mime-16.1 {cleanly { }} { set res {} set mime [mime::initialize -canonical text/plain -string {dawg one}] mime::header set $mime Content-Disposition attachment [list param1 $char] set msg [mime::serialize $mime] regsub {(Content-ID: <).*(>)} $msg {\1\2} msg lappend res $msg set mime2 [mime::initialize -string $msg] lappend res [mime::header get $mime2] return $res } [list "MIME-Version: 1.0\r Content-ID: <>\r Content-Type: text/plain\r Content-Disposition: attachment\r ; param1*0*=utf-8''%E3%81%AF\r \r dawg one" \ [list MIME-Version {1.0 {}} Content-ID {<> {}} Content-Type {text/plain {}} \ Content-Disposition [list attachment [list param1 $char]]] ] testsuiteCleanup set [namespace current]::done 1 return } after 0 [list ::coroutine [info cmdcount]_main [namespace current]::main] vwait [namespace current]::done return |
Changes to modules/mime/pkgIndex.tcl.
1 2 3 | if {![package vsatisfies [package provide Tcl] 8.3]} {return} package ifneeded smtp 1.5 [list source [file join $dir smtp.tcl]] if {![package vsatisfies [package provide Tcl] 8.5]} {return} | | | 1 2 3 4 | if {![package vsatisfies [package provide Tcl] 8.3]} {return} package ifneeded smtp 1.5 [list source [file join $dir smtp.tcl]] if {![package vsatisfies [package provide Tcl] 8.5]} {return} package ifneeded mime 1.7 [list source [file join $dir mime.tcl]] |
Changes to modules/mime/smtp.tcl.
1 2 3 4 5 6 7 8 9 10 | # smtp.tcl - SMTP client # # Copyright (c) 1999-2000 Marshall T. Rose # Copyright (c) 2003-2006 Pat Thoyts # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # package require Tcl 8.3 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # smtp.tcl - SMTP client # # Copyright (c) 1999-2000 Marshall T. Rose # Copyright (c) 2003-2006 Pat Thoyts # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # package require Tcl 8.3 package require mime 1.7- catch { package require SASL 1.0; # tcllib 1.8 package require SASL::NTLM 1.0; # tcllib 1.8 } # |
︙ | ︙ | |||
382 383 384 385 386 387 388 | lappend vrecipients $aprops(address) } # If there's no date header, get the date from the mime message. Same for # the message-id. if {([lsearch -exact $lowerL $dateL] < 0) \ | | | | > | | 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 | lappend vrecipients $aprops(address) } # If there's no date header, get the date from the mime message. Same for # the message-id. if {([lsearch -exact $lowerL $dateL] < 0) \ && ([catch {::mime::header get $part $dateL}])} { lappend lowerL $dateL lappend mixedL $dateM lappend header($dateL) [::mime::parsedatetime -now proper] } if {([lsearch -exact $lowerL ${message-idL}] < 0) \ && ([catch {::mime::header get $part ${message-idL}}])} { lappend lowerL ${message-idL} lappend mixedL ${message-idM} lappend header(${message-idL}) [::mime::uniqueID] } # Get all the headers from the MIME object and save them so that they can # later be restored. set savedH [::mime::header get $part] puts [list crackle $savedH] # Take all the headers defined earlier and add them to the MIME message. foreach lower $lowerL mixed $mixedL { foreach value $header($lower) { ::mime::header set $part $mixed $value -mode append } } if {[string length $client] < 1} { if {![string compare $servers localhost]} { set client localhost } else { |
︙ | ︙ | |||
440 441 442 443 444 445 446 | set ecode $errorCode set einfo $errorInfo # Send the message to bcc recipients as a MIME attachment. if {($code == 0) && ($bccP)} { set inner [::mime::initialize -canonical message/rfc822 \ | | | | < | | > | | | < | | | 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 | set ecode $errorCode set einfo $errorInfo # Send the message to bcc recipients as a MIME attachment. if {($code == 0) && ($bccP)} { set inner [::mime::initialize -canonical message/rfc822 \ -headers [list Content-Description \ {Original Message}] \ -parts [list $part]] set subject "\[$bccM\]" if {[info exists header(subject)]} { append subject " " [lindex $header(subject) 0] } set outer [::mime::initialize \ -canonical multipart/digest \ -headers [list \ From [list $originator {}] \ Bcc Date [::mime::parsedatetime -now proper] \ Subject $subject \ Message-ID [::mime::uniqueID] \ Content-Description {Blind Carbon Copy} \ -parts [list $inner]] set code [catch { sendmessageaux $token $outer \ $sender $brecipients \ $aloP } result2] set ecode $errorCode set einfo $errorInfo |
︙ | ︙ | |||
500 501 502 503 504 505 506 | default { set status abort } } # Destroy SMTP token 'cause we're done with it. | | | | | < | | | | < | 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 | default { set status abort } } # Destroy SMTP token 'cause we're done with it. catch { finalize $token -close $status } copts cres # Restore provided MIME object to original state (without the SMTP headers). foreach key [::mime::header get $part -names] { mime::header set $part $key "" -mode delete } foreach {key value} $savedH { ::mime::header set $part $key {*}$value -mode append } retuern -options $copts $cres } # ::smtp::sendmessageaux -- # # Sends a mime object (containing a message) to some recipients using an # existing SMTP token. # |
︙ | ︙ |
Changes to modules/namespacex/namespacex.man.
︙ | ︙ | |||
26 27 28 29 30 31 32 | [call [cmd {::namespacex hook add}] [opt [arg namespace]] [arg cmdprefix]] [call [cmd {::namespacex hook proc}] [opt [arg namespace]] [arg arguments] [arg body]] [call [cmd {::namespacex hook on}] [opt [arg namespace]] [arg guardcmdprefix] [arg actioncmdprefix]] [call [cmd {::namespacex hook next}] [arg arg]...] [call [cmd {::namespacex info allchildren}] [arg namespace]] | | | | > > > > > | | | > > > > > > > | 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 | [call [cmd {::namespacex hook add}] [opt [arg namespace]] [arg cmdprefix]] [call [cmd {::namespacex hook proc}] [opt [arg namespace]] [arg arguments] [arg body]] [call [cmd {::namespacex hook on}] [opt [arg namespace]] [arg guardcmdprefix] [arg actioncmdprefix]] [call [cmd {::namespacex hook next}] [arg arg]...] [call [cmd {::namespacex info allchildren}] [arg namespace]] Returns a list containing the names of all child namespaces in the specified [arg namespace] and its children. The names are all fully qualified. [call [cmd {::namespacex info allvars}] [arg namespace]] Returns a list containing the names of all variables in the specified [arg namespace] and its children. The names are all relative to [arg namespace], and [emph not] fully qualified. [call [cmd {::namespacex info vars}] [arg namespace] [opt [arg pattern]]] Returns a list containing the names of all variables in the specified [arg namespace]. [call [cmd {::namespacex normalize}] [arg namespace]] Returns the absolute name of [arg namespace], which is resolved relative to the namespace of the caller, with all unneeded colon characters removed. [call [cmd {::namespacex state get}] [arg namespace]] Returns a dictionary holding the names and values of all variables in the specified [arg namespace] and its child namespaces. [para] Note that the names are all relative to [arg namespace], and [emph not] fully qualified. [call [cmd {::namespacex state set}] [arg namespace] [arg dict]] Takes a dictionary holding the names and values for a set of variables and replaces the current state of the specified [arg namespace] and its child namespaces with this state. The result of the command is the empty string. [call [cmd {::namespacex state drop}] [arg namespace]] Unsets all variables in the specified [arg namespace] and its child namespaces. The result of the command is the empty string. [call [cmd {::namespacex strip}] [arg namespace] [arg namespaces]] Each item in [arg namespaces] must be the absolute normalized name of a child namespace of [arg prefix]. Returns the corresponding list of relative names of child namespaces. [list_end] [manpage_end] |
Changes to modules/namespacex/namespacex.tcl.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # # ## ### ##### ######## ############# ###################### ## Requisites package require Tcl 8.5 ; # namespace ensembles, {*} namespace eval ::namespacex { | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # # ## ### ##### ######## ############# ###################### ## Requisites package require Tcl 8.5 ; # namespace ensembles, {*} namespace eval ::namespacex { namespace export add hook info normalize strip state namespace ensemble create namespace eval hook { namespace export add proc on next namespace ensemble create # add - hook a command prefix into the chain of unknown handlers for a |
︙ | ︙ | |||
179 180 181 182 183 184 185 | return -code $rc $result } } # # ## ### ##### ######## ############# ###################### ## Implementation :: Info - Visible API | > | | | > | | > > | > > | | > > | > > > > > | | > > > > > | | | | | > | 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 | return -code $rc $result } } # # ## ### ##### ######## ############# ###################### ## Implementation :: Info - Visible API proc ::namespacex::info::allvars ns { set ns [uplevel 1 [list [namespace parent] normalize $ns]] ::set result [::info vars ${ns}::*] foreach cns [allchildren $ns] { lappend result {*}[::info vars ${cns}::*] } return [[namespace parent] strip $ns $result] } proc ::namespacex::info::allchildren ns { set ns [uplevel 1 [list [namespace parent] normalize $ns]] ::set result [list] foreach cns [::namespace children $ns] { lappend result {*}[allchildren $cns] lappend result $cns } return $result } proc ::namespacex::info::vars {ns {pattern *}} { set ns [uplevel 1 [list [namespace parent] normalize $ns]] return [[namespace parent] strip $ns [::info vars ${ns}::$pattern]] } # this implementation avoids string operations proc ::namespacex::normalize ns { if {[uplevel 1 [list ::namespace exists $ns]]} { return [uplevel 1 [list namespace eval $ns {::namespace current}]] } if {![string match ::* $ns]} { set ns [uplevel 1 {::namespace current}]::$ns } regsub {::+} $ns :: ns return $ns } proc ::namespacex::strip {ns itemlist} { set n [string length $ns] if {$ns ne {::}} { incr n 2 } set result {} foreach i $itemlist { lappend result [string range $i $n end] } return $result } # # ## ### ##### ######## ############# ###################### ## Implementation :: State - Visible API proc ::namespacex::state::drop ns { ::set ns [uplevel 1 [list [namespace parent] normalize $ns]] namespace eval $ns [list ::unset {*}[::namespacex info allvars $ns]] return } proc ::namespacex::state::get ns { ::set ns [uplevel 1 [list [namespace parent] normalize $ns]] ::set result {} foreach v [::namespacex info allvars $ns] { namespace upvar $ns $v value lappend result $v $value } return $result } proc ::namespacex::state::set {ns state} { ::set ns [uplevel 1 [list [namespace parent] normalize $ns]] # Inlined 'state drop'. namespace eval $ns [list ::unset {*}[::namespacex info allvars $ns]] namespace eval $ns [list variable {*}$state] return } # # ## ### ##### ######## ############# ###################### ## Ready package provide namespacex 0.1 |
Changes to modules/namespacex/namespacex.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | testing { useLocal namespacex.tcl namespacex } # ------------------------------------------------------------------------- | > > | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | > | | | > | | | | | | > | | | | | | | | | > | | | > | | | > | | | | | | | > | | | | | | | > | | | | | | | | > | | | > | | | > | | | | | | | > | | | | | | | > | | | | | | | > | | | | | | | > | | | | | | | > | | | | | | | | > | | | > | | | > | | | | | | | > | | | | | | | > | | | | | | | > | | | | | | | > | | | | | | | > | | | | | | | | > | | | > | | | > | | | | | | | | > | | | | | | | | > | | | | | | | | > | | | | | | | | > | | | | | | | | > | | | | | | | | | > | | | > | | | > | | | > | | | | | | | | | | > | | | | | | | | | | > | | | | | | | | | | > | | | | | | | | | | | | | | | | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | testing { useLocal namespacex.tcl namespacex } # ------------------------------------------------------------------------- namespace eval Q { proc ns_setup {} { namespace eval X { namespace eval A {} namespace eval B { namespace eval D {} } namespace eval C {} } } proc ns2_setup {} { namespace eval X::Y { variable vXa 1 variable vXb aleph namespace eval B { variable vB 3 } } } proc ns3_setup {} { namespace eval X { namespace eval B { variable vB mjolnir } } } # ------------------------------------------------------------------------- test namespacex-info-allchildren-1.0 {namespacex info allchildren, wrong\#args} -body { namespacex info allchildren } -returnCodes error -result {wrong # args: should be "namespacex info allchildren ns"} test namespacex-info-allchildren-1.1 {namespacex info allchildren, wrong\#args} -body { namespacex info allchildren N X } -returnCodes error -result {wrong # args: should be "namespacex info allchildren ns"} test namespacex-info-allchildren-2.0.0 {namespacex info allchildren} -setup { ns_setup } -body { lsort -dict [namespacex strip [namespace current] [namespacex info allchildren X]] } -cleanup { namespace delete X } -result {X::A X::B X::B::D X::C} test namespacex-info-allchildren-2.0.1 {namespacex info allchildren} -setup { ns_setup } -body { lsort -dict [namespacex strip [namespace current] [namespacex info allchildren X]] } -cleanup { namespace delete X } -result {X::A X::B X::B::D X::C} # ------------------------------------------------------------------------- test namespacex-info-vars-1.0 {namespacex info vars, wrong\#args} -body { namespacex info vars } -returnCodes error -result {wrong # args: should be "namespacex info vars ns ?pattern?"} test namespacex-info-vars-1.1 {namespacex info vars, wrong\#args} -body { namespacex info vars N P X } -returnCodes error -result {wrong # args: should be "namespacex info vars ns ?pattern?"} test namespacex-info-vars-2.0 {namespacex info vars} -setup { ns2_setup } -body { lsort -dict [namespacex info vars X::::Y] } -cleanup { namespace delete X } -result {vXa vXb} test namespacex-info-vars-2.1 {namespacex info vars} -setup { namespace eval X {} } -body { lsort -dict [namespacex info vars X] } -cleanup { namespace delete X } -result {} test namespacex-info-vars-2.2 {namespacex info vars} -setup { ns3_setup } -body { lsort -dict [namespacex info vars X] } -cleanup { namespace delete X } -result {} # ------------------------------------------------------------------------- test namespacex-info-allvars-1.0 {namespacex info allvars, wrong\#args} -body { namespacex info allvars } -returnCodes error -result {wrong # args: should be "namespacex info allvars ns"} test namespacex-info-allvars-1.1 {namespacex info allvars, wrong\#args} -body { namespacex info allvars N X } -returnCodes error -result {wrong # args: should be "namespacex info allvars ns"} test namespacex-info-allvars-2.0.0 {namespacex info allvars} -setup { ns2_setup } -body { lsort -dict [namespacex info allvars X::::Y] } -cleanup { namespace delete X } -result {B::vB vXa vXb} test namespacex-info-allvars-2.0.1 {namespacex info allvars} -setup { ns2_setup } -body { lsort -dict [namespacex info allvars X::Y] } -cleanup { namespace delete X } -result {B::vB vXa vXb} test namespacex-info-allvars-2.1.0 {namespacex info allvars} -setup { namespace eval X {} } -body { lsort -dict [namespacex info allvars X] } -cleanup { namespace delete X } -result {} test namespacex-info-allvars-2.1.1 {namespacex info allvars} -setup { namespace eval X {} } -body { lsort -dict [namespacex info allvars X] } -cleanup { namespace delete X } -result {} test namespacex-info-allvars-2.2.0 {namespacex info allvars} -setup { ns3_setup } -body { lsort -dict [namespacex info allvars X] } -cleanup { namespace delete X } -result {B::vB} test namespacex-info-allvars-2.2.1 {namespacex info allvars} -setup { ns3_setup } -body { lsort -dict [namespacex info allvars X] } -cleanup { namespace delete X } -result {B::vB} # ------------------------------------------------------------------------- test namespacex-state-get-1.0 {namespacex state get, wrong\#args} -body { namespacex state get } -returnCodes error -result {wrong # args: should be "namespacex state get ns"} test namespacex-state-get-1.1 {namespacex state get, wrong\#args} -body { namespacex state get N X } -returnCodes error -result {wrong # args: should be "namespacex state get ns"} test namespacex-state-get-2.0.0 {namespacex state get} -setup { ns2_setup } -body { dictsort [namespacex state get X::Y] } -cleanup { namespace delete X } -result {B::vB 3 vXa 1 vXb aleph} test namespacex-state-get-2.0.1 {namespacex state get} -setup { ns2_setup } -body { dictsort [namespacex state get X::Y] } -cleanup { namespace delete X } -result {B::vB 3 vXa 1 vXb aleph} test namespacex-state-get-2.1.0 {namespacex state get} -setup { namespace eval ::X {} } -body { dictsort [namespacex state get ::X] } -cleanup { namespace delete ::X } -result {} test namespacex-state-get-2.1.1 {namespacex state get} -setup { namespace eval X {} } -body { dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {} test namespacex-state-get-2.2.0 {namespacex state get} -setup { ns3_setup } -body { dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {B::vB mjolnir} test namespacex-state-get-2.2.1 {namespacex state get} -setup { ns3_setup } -body { dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {B::vB mjolnir} # ------------------------------------------------------------------------- test namespacex-state-drop-1.0 {namespacex state drop, wrong\#args} -body { namespacex state drop } -returnCodes error -result {wrong # args: should be "namespacex state drop ns"} test namespacex-state-drop-1.1 {namespacex state drop, wrong\#args} -body { namespacex state drop N X } -returnCodes error -result {wrong # args: should be "namespacex state drop ns"} test namespacex-state-drop-2.0.0 {namespacex state drop} -setup { ns2_setup } -body { namespacex state drop X dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {} test namespacex-state-drop-2.0.1 {namespacex state drop} -setup { ns2_setup } -body { namespacex state drop X dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {} test namespacex-state-drop-2.1.0 {namespacex state drop} -setup { namespace eval X {} } -body { namespacex state drop X dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {} test namespacex-state-drop-2.1.1 {namespacex state drop} -setup { namespace eval X {} } -body { namespacex state drop X dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {} test namespacex-state-drop-2.2.0 {namespacex state drop} -setup { ns3_setup } -body { namespacex state drop X dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {} test namespacex-state-drop-2.2.1 {namespacex state drop} -setup { ns3_setup } -body { namespacex state drop X dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {} # ------------------------------------------------------------------------- test namespacex-state-set-1.0 {namespacex state set, wrong\#args} -body { namespacex state set } -returnCodes error -result {wrong # args: should be "namespacex state set ns state"} test namespacex-state-set-1.1 {namespacex state set, wrong\#args} -body { namespacex state set N } -returnCodes error -result {wrong # args: should be "namespacex state set ns state"} test namespacex-state-set-1.2 {namespacex state set, wrong\#args} -body { namespacex state set N S X } -returnCodes error -result {wrong # args: should be "namespacex state set ns state"} test namespacex-state-set-2.0.0 {namespacex state set} -setup { ns2_setup set ST [namespacex state get X::Y] ns3_setup } -body { namespacex state set X::Y $ST dictsort [namespacex state get X::Y] } -cleanup { namespace delete X } -result {B::vB 3 vXa 1 vXb aleph} test namespacex-state-set-2.0.1 {namespacex state set} -setup { ns2_setup set ST [namespacex state get X::Y] ns3_setup } -body { namespacex state set X::Y $ST dictsort [namespacex state get X::Y] } -cleanup { namespace delete X::Y } -result {B::vB 3 vXa 1 vXb aleph} test namespacex-state-set-2.1.0 {namespacex state set} -setup { ns3_setup set ST [namespacex state get X] ns2_setup } -body { namespacex state set X $ST dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {B::vB mjolnir} test namespacex-state-set-2.1.1 {namespacex state set} -setup { ns3_setup set ST [namespacex state get X] ns2_setup } -body { namespacex state set X $ST dictsort [namespacex state get X] } -cleanup { namespace delete X } -result {B::vB mjolnir} # ------------------------------------------------------------------------- testsuiteCleanup # Local variables: # mode: tcl # indent-tabs-mode: nil # End: } |
Changes to modules/ncgi/ncgi.tcl.
︙ | ︙ | |||
811 812 813 814 815 816 817 | # # Results: # A two-element list, the first is the primary value, # the second is in turn a name-value list corresponding to the # parameters. Given the above example, the return value is # { # value | | | < | > | < | 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 | # # Results: # A two-element list, the first is the primary value, # the second is in turn a name-value list corresponding to the # parameters. Given the above example, the return value is # { # value # {param value param2 value2 param3 value3} # } proc ::ncgi::parseMimeValue {value} { set parts [split $value \;] set results [list [string trim [lindex $parts 0]]] set paramList [list] foreach sub [lrange $parts 1 end] { if {[regexp -- {([^=]+)=(.+)} $sub match key val]} { set key [string trim [string tolower $key]] set val [string trim $val] # Allow single as well as double quotes if {[regexp -- {^(['"])(.*)\1} $val x quote val2]} { ; # need a " for balance # Trim quotes and any extra crap after close quote # remove quoted quotation marks set val [string map {\\" "\"" \\' "\'"} $val2] } lappend paramList $key $val } } if {[llength $paramList]} { lappend results $paramList } |
︙ | ︙ |
Changes to modules/ncgi/ncgi.test.
︙ | ︙ | |||
573 574 575 576 577 578 579 580 581 582 583 584 585 586 | test ncgi-13.5 {ncgi::parseMimeValue} { ncgi::parseMimeValue "text/html; charset=\"iso-8859-1\"; ignored" } {text/html {charset iso-8859-1}} test ncgi-13.6 {ncgi::parseMimeValue} { ncgi::parseMimeValue "text/html; charset=\"iso-8859-1\"morecrap" } {text/html {charset iso-8859-1}} test ncgi-14.1 {ncgi::multipart} { catch {ncgi::multipart "application/x-www-urlencoded" name=val+ue} err set err } {Not a multipart Content-Type: application/x-www-urlencoded} | > > > > > > > > | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | test ncgi-13.5 {ncgi::parseMimeValue} { ncgi::parseMimeValue "text/html; charset=\"iso-8859-1\"; ignored" } {text/html {charset iso-8859-1}} test ncgi-13.6 {ncgi::parseMimeValue} { ncgi::parseMimeValue "text/html; charset=\"iso-8859-1\"morecrap" } {text/html {charset iso-8859-1}} test ncgi-13.7 {ncgi::parseMimeValue} { ncgi::parseMimeValue {test/test; foo="bar\"baz\""} } {test/test {foo bar\"baz\"}} test ncgi-13.8 {ncgi::parseMimeValue} { ncgi::parseMimeValue {test/test; foo=""} } {test/test {foo {}}} test ncgi-14.1 {ncgi::multipart} { catch {ncgi::multipart "application/x-www-urlencoded" name=val+ue} err set err } {Not a multipart Content-Type: application/x-www-urlencoded} |
︙ | ︙ |
Changes to modules/nns/nns_client.man.
︙ | ︙ | |||
132 133 134 135 136 137 138 | In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section [sectref OPTIONS]. [call [cmd ::nameserv::configure] [option -option]] In this form the command is an alias for | | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section [sectref OPTIONS]. [call [cmd ::nameserv::configure] [option -option]] In this form the command is an alias for "[cmd ::nameserv::cget] [option -option]". The list of supported options and their meaning can be found in section [sectref OPTIONS]. [call [cmd ::nameserv::configure] "[option -option] [arg value]..."] In this form the command is used to configure one or more of the |
︙ | ︙ |
Changes to modules/nns/nns_server.man.
︙ | ︙ | |||
76 77 78 79 80 81 82 | In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section [sectref OPTIONS]. [call [cmd ::nameserv::server::configure] [option -option]] In this form the command is an alias for | | | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | In this form the command returns a dictionary of all supported options, and their current values. The list of supported options and their meaning can be found in section [sectref OPTIONS]. [call [cmd ::nameserv::server::configure] [option -option]] In this form the command is an alias for "[cmd ::nameserv::server::cget] [option -option]". The list of supported options and their meaning can be found in section [sectref OPTIONS]. [call [cmd ::nameserv::server::configure] "[option -option] [arg value]..."] In this form the command is used to configure one or more of the |
︙ | ︙ |
Changes to modules/oodialect/oodialect.tcl.
1 2 3 4 5 6 7 8 9 | ### # oodialect.tcl # # Copyright (c) 2015-2018 Sean Woods # Copyright (c) 2015 Donald K Fellows # # BSD License ### # @@ Meta Begin | | < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ### # oodialect.tcl # # Copyright (c) 2015-2018 Sean Woods # Copyright (c) 2015 Donald K Fellows # # BSD License ### # @@ Meta Begin # Package oo::dialect 0.3.4 # Meta platform tcl # Meta summary A utility for defining a domain specific language for TclOO systems # Meta description This package allows developers to generate # Meta description domain specific languages to describe TclOO # Meta description classes and objects. # Meta category TclOO # Meta subject oodialect # Meta require {Tcl 8.6} # Meta author Sean Woods # Meta author Donald K. Fellows # Meta license BSD # @@ Meta End namespace eval ::oo::dialect { namespace export create } # A stack of class names proc ::oo::dialect::Push {class} { ::variable class_stack |
︙ | ︙ | |||
75 76 77 78 79 80 81 | # We should begin with that ### set pnspace [NSNormalize [uplevel 1 {namespace current}] $parent] apply [list parent { ::namespace export dynamic_methods ::namespace import -force ${parent}::dynamic_methods } $NSPACE] $pnspace | | | | | 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 | # We should begin with that ### set pnspace [NSNormalize [uplevel 1 {namespace current}] $parent] apply [list parent { ::namespace export dynamic_methods ::namespace import -force ${parent}::dynamic_methods } $NSPACE] $pnspace apply [list parent { ::namespace import -force ${parent}::define::* ::namespace export * } ${NSPACE}::define] $pnspace set ANCESTORS [list ${pnspace}::object] } ### # Build our dialect template functions ### proc ${NSPACE}::define {oclass args} [string map [list %NSPACE% $NSPACE] { ### # To facilitate library reloading, allow # a dialect to create a class from DEFINE ### set class [::oo::dialect::NSNormalize [uplevel 1 {namespace current}] $oclass] if {[info commands $class] eq {}} { %NSPACE%::class create $class {*}${args} } else { ::oo::dialect::Define %NSPACE% $class {*}${args} } }] interp alias {} ${NSPACE}::define::current_class {} \ ::oo::dialect::Peek |
︙ | ︙ | |||
129 130 131 132 133 134 135 | ### uplevel #0 [string map [list %NSPACE% [list $NSPACE] %name% [list $name] %ANCESTORS% $ANCESTORS] { %NSPACE%::class create %NSPACE%::object { superclass %ANCESTORS% # Put MOACish stuff in here } }] | < | | | | | < | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | ### uplevel #0 [string map [list %NSPACE% [list $NSPACE] %name% [list $name] %ANCESTORS% $ANCESTORS] { %NSPACE%::class create %NSPACE%::object { superclass %ANCESTORS% # Put MOACish stuff in here } }] if { "${NSPACE}::class" ni $::oo::dialect::core_classes } { lappend ::oo::dialect::core_classes "${NSPACE}::class" } if { "${NSPACE}::object" ni $::oo::dialect::core_classes } { lappend ::oo::dialect::core_classes "${NSPACE}::object" } } # Support commands; not intended to be called directly. proc ::oo::dialect::NSNormalize {namespace qualname} { if {![string match ::* $qualname]} { set qualname ${namespace}::$qualname |
︙ | ︙ | |||
258 259 260 261 262 263 264 | method aliases {} { if {[info exists ::oo::dialect::aliases([self])]} { return $::oo::dialect::aliases([self]) } } } | > > > > | | 253 254 255 256 257 258 259 260 261 262 263 264 | method aliases {} { if {[info exists ::oo::dialect::aliases([self])]} { return $::oo::dialect::aliases([self]) } } } namespace eval ::oo::dialect { variable core_classes {::oo::class ::oo::object} } package provide oo::dialect 0.3.4 |
Changes to modules/oodialect/pkgIndex.tcl.
|
| | | 1 | package ifneeded oo::dialect 0.3.4 [list source [file join $dir oodialect.tcl]] |
Changes to modules/oometa/oometa.man.
︙ | ︙ | |||
136 137 138 139 140 141 142 | produce a local picture of metadata. This method provides the following additional commands: [call [cmd {oo::object method meta cget}] [opt [arg field]] [opt [arg ...]] [arg field]] Attempts to locate a singlar leaf, and return its value. For single option lookups, this | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | produce a local picture of metadata. This method provides the following additional commands: [call [cmd {oo::object method meta cget}] [opt [arg field]] [opt [arg ...]] [arg field]] Attempts to locate a singlar leaf, and return its value. For single option lookups, this is faster than [cmd {my meta getnull}] [opt [arg field]] [opt [arg ...]] [arg field], because it performs a search instead directly instead of producing the recursive merge product between the class metadata, the local [emph meta] variable, and THEN performing the search. [list_end] [vset CATEGORY tcloo] [include ../doctools2base/include/feedback.inc] |
︙ | ︙ |
Changes to modules/oometa/oometa.tcl.
1 2 3 4 5 6 7 | ### # Author: Sean Woods, [email protected] ## # TclOO routines to implement property tracking by class and object ### package require Tcl 8.6 ;# tailcall package require dicttool | > | | < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | ### # Author: Sean Woods, [email protected] ## # TclOO routines to implement property tracking by class and object ### package require Tcl 8.6 ;# tailcall package require dicttool package require oo::dialect package provide oo::meta 0.7.2 namespace eval ::oo::meta { set dirty_classes {} } proc ::oo::meta::args_to_dict args { if {[llength $args]==1} { return [lindex $args 0] } return $args } proc ::oo::meta::args_to_options args { set result {} foreach {var val} [args_to_dict {*}$args] { lappend result [string trimleft $var -] $val } return $result } proc ::oo::meta::ancestors class { set class [::oo::meta::normalize $class] set core_result {} set queue $class set result {} # Rig things such that that the top superclasses # are evaluated first while {[llength $queue]} { set tqueue $queue set queue {} foreach qclass $tqueue { if {$qclass in $::oo::dialect::core_classes} { if {$qclass ni $core_result} { lappend core_result $qclass } continue } foreach aclass [::info class superclasses $qclass] { if { $aclass in $result } continue |
︙ | ︙ | |||
178 179 180 181 182 183 184 | } dump { set info [metadata $class] return $info } default { set info [metadata $class] | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | } dump { set info [metadata $class] return $info } default { set info [metadata $class] return [::dict $submethod $info {*}$args] } } } proc ::oo::meta::localdata {class args} { if {![::info exists ::oo::meta::local_property($class)]} { return {} |
︙ | ︙ | |||
216 217 218 219 220 221 222 | if {$dclass in $cancestors} { unset -nocomplain ::oo::meta::cached_property($cclass) unset -nocomplain ::oo::meta::cached_hierarchy($cclass) } } if {![::info exists ::oo::meta::local_property($dclass)]} continue if {[dict getnull $::oo::meta::local_property($dclass) classinfo type:] eq "core"} { | | | | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | if {$dclass in $cancestors} { unset -nocomplain ::oo::meta::cached_property($cclass) unset -nocomplain ::oo::meta::cached_hierarchy($cclass) } } if {![::info exists ::oo::meta::local_property($dclass)]} continue if {[dict getnull $::oo::meta::local_property($dclass) classinfo type:] eq "core"} { if {$dclass ni $::oo::dialect::core_classes} { lappend ::oo::dialect::core_classes $dclass } } } set dirty_classes {} } ### |
︙ | ︙ | |||
492 493 494 495 496 497 498 | } } default { foreach mclass $classlist { lappend mdata [::oo::meta::metadata $mclass] } set info [dict rmerge {*}$mdata $meta] | | | 491 492 493 494 495 496 497 498 499 500 501 502 | } } default { foreach mclass $classlist { lappend mdata [::oo::meta::metadata $mclass] } set info [dict rmerge {*}$mdata $meta] return [dict $submethod $info {*}$args] } } } } |
Changes to modules/oometa/pkgIndex.tcl.
1 2 3 4 5 6 | #checker -scope global exclude warnUndefinedVar # var in question is 'dir'. if {![package vsatisfies [package provide Tcl] 8.6]} { # PRAGMA: returnok return } | | | 1 2 3 4 5 6 7 8 | #checker -scope global exclude warnUndefinedVar # var in question is 'dir'. if {![package vsatisfies [package provide Tcl] 8.6]} { # PRAGMA: returnok return } package ifneeded oo::meta 0.7.2 [list source [file join $dir oometa.tcl]] package ifneeded oo::option 0.3.1 [list source [file join $dir oooption.tcl]] |
Changes to modules/pop3d/pop3d.man.
︙ | ︙ | |||
201 202 203 204 205 206 207 | callback so that pop3 servers following the interface of this module are able to use it. The [arg mbox] argument is the storage reference as returned by the [method lookup] method of the authentication command, see section [sectref Authentication]. [list_begin definitions] | | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | callback so that pop3 servers following the interface of this module are able to use it. The [arg mbox] argument is the storage reference as returned by the [method lookup] method of the authentication command, see section [sectref Authentication]. [list_begin definitions] [call [arg storageCmd] [method dele] [arg mbox] [arg msgList]] Deletes the messages whose numeric ids are contained in the [arg msgList] from the mailbox specified via [arg mbox]. [call [arg storageCmd] [method lock] [arg mbox]] This method locks the specified mailbox for use by a single connection |
︙ | ︙ |
Changes to modules/practcl/build/build.tcl.
1 2 | set srcdir [file dirname [file normalize [file join [pwd] [info script]]]] set moddir [file dirname $srcdir] | > > | > > | | > | | | | | | | | | | > < > > | < > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | set srcdir [file dirname [file normalize [file join [pwd] [info script]]]] set moddir [file dirname $srcdir] if {[catch {package require clay 0.3}]} { source [file join $$moddir .. clay build doctool.tcl] } ::clay::doctool create AutoDoc set version 0.13 set tclversion 8.6 set module [file tail $moddir] set filename $module set fout [open [file join $moddir $filename.tcl] w] fconfigure $fout -translation lf dict set map %module% $module dict set map %version% $version dict set map %tclversion% $tclversion #dict set map { } {} #dict set map "\t" { } puts $fout [string map $map {### # Amalgamated package for %module% # Do not edit directly, tweak the source in src/ and rerun # build.tcl ### package require Tcl %tclversion% package provide %module% %version% namespace eval ::%module% {} }] # Track what files we have included so far set loaded {} # These files must be loaded in a particular order ### # Load other module code that this module will need ### foreach {omod files} { httpwget wget.tcl clay {build/procs.tcl build/class.tcl build/object.tcl build/doctool.tcl} } { foreach fname $files { set file [file join $moddir .. $omod $fname] puts $fout "###\n# START: [file join $omod $fname]\n###" set content [::clay::cat [file join $moddir .. $omod $fname]] #AutoDoc scan_text $content puts $fout $content puts $fout "###\n# END: [file join $omod $fname]\n###" } } foreach file { setup.tcl docbuild.tcl buildutil.tcl fileutil.tcl installutil.tcl makeutil.tcl {class metaclass.tcl} {class toolset baseclass.tcl} |
︙ | ︙ | |||
74 75 76 77 78 79 80 | {class subproject binary.tcl} {class subproject core.tcl} {class tool.tcl} } { lappend loaded $file | < > > | < < > > > > > > > | 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 | {class subproject binary.tcl} {class subproject core.tcl} {class tool.tcl} } { lappend loaded $file puts $fout "###\n# START: [file join $file]\n###" set content [::clay::cat [file join $srcdir {*}$file]] AutoDoc scan_text $content puts $fout $content puts $fout "###\n# END: [file join $file]\n###" } # Provide some cleanup and our final package provide puts $fout [string map $map { namespace eval ::%module% { namespace export * } }] close $fout ### # Build our pkgIndex.tcl file ### set fout [open [file join $moddir pkgIndex.tcl] w] fconfigure $fout -translation lf puts $fout [string map $map {### if {![package vsatisfies [package provide Tcl] %tclversion%]} {return} package ifneeded %module% %version% [list source [file join $dir %module%.tcl]] }] close $fout set manout [open [file join $moddir $filename.man] w] puts $manout [AutoDoc manpage \ header [string map $map [::clay::cat [file join $srcdir manual.txt]]] \ footer [string map $map [::clay::cat [file join $srcdir footer.txt]]] \ ] close $manout |
Changes to modules/practcl/build/buildutil.tcl.
1 2 3 4 5 6 7 8 9 10 11 | ### # 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 ### | > > > > > > > > < | < | 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 | ### # 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 } ### |
︙ | ︙ | |||
97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 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] | > > > > > > > > > > > > > > > | 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 | 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] |
︙ | ︙ | |||
123 124 125 126 127 128 129 | proc ::practcl::sort_dict list { set result {} foreach key [lsort -dictionary [dict keys $list]] { dict set result $key [dict get $list $key] } return $result } | < < < < | < < | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 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/metaclass.tcl.
︙ | ︙ | |||
64 65 66 67 68 69 70 | } default { array $submethod define {*}$args } } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | } default { array $submethod define {*}$args } } } method graft args { return [my clay delegate {*}$args] } method initialize {} {} method link {command args} { my variable links |
︙ | ︙ | |||
275 276 277 278 279 280 281 | foreach {s c} $mixinslot { if {$c eq {}} continue lappend mixins $c } oo::objdefine [self] mixin {*}$mixins } | | < < | < < < < < < < | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | foreach {s c} $mixinslot { if {$c eq {}} continue lappend mixins $c } oo::objdefine [self] mixin {*}$mixins } method organ args { return [my clay delegate {*}$args] } method script script { eval $script } method select {} { |
︙ | ︙ |
Changes to modules/practcl/build/class/module.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 | ### # 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 ### ::oo::class create ::practcl::module { superclass ::practcl::object ::practcl::product.dynamic method _MorphPatterns {} { return {{@name@} {::practcl::module.@name@} ::practcl::module} } | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ### # 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 ### ::oo::class create ::practcl::module { superclass ::practcl::object ::practcl::product.dynamic method _MorphPatterns {} { return {{@name@} {::practcl::module.@name@} ::practcl::module} } method add args { my variable links set object [::practcl::object new [self] {*}$args] foreach linktype [$object linktype] { lappend links($linktype) $object } return $object } method install-headers args {} ### # Target handling ### method make {command args} { my variable make_object if {![info exists make_object]} { set make_object {} |
︙ | ︙ | |||
119 120 121 122 123 124 125 | } task - target - add { set name [lindex $args 0] set info [uplevel #0 [list subst [lindex $args 1]]] set body [lindex $args 2] | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | } task - target - add { set name [lindex $args 0] set info [uplevel #0 [list subst [lindex $args 1]]] set body [lindex $args 2] set nspace [namespace current] if {[dict exist $make_object $name]} { set obj [dict get $$make_object $name] } else { set obj [::practcl::make_obj new [self] $name $info $body] dict set make_object $name $obj dict set target_make $name 0 |
︙ | ︙ | |||
143 144 145 146 147 148 149 | return $obj } todo { foreach {name obj} $make_object { if {[$obj do]} { lappend result $name } | | | > | 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 | return $obj } todo { foreach {name obj} $make_object { if {[$obj do]} { lappend result $name } } } do { global CWD SRCDIR project SANDBOX foreach {name obj} $make_object { if {[$obj do]} { eval [$obj define get action] } } } } } method child which { switch $which { delegate - organs { return [list project [my define get project] module [self]] } } } ### |
︙ | ︙ | |||
335 336 337 338 339 340 341 | lappend errs [dict get $errdat -errorinfo] } else { lappend errs $errdat } } } if {[llength $errs]} { | | | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | lappend errs [dict get $errdat -errorinfo] } else { lappend errs $errdat } } } if {[llength $errs]} { set logfile [file join $::CWD practcl.log] ::practcl::log $logfile "*** ERRORS ***" foreach {item trace} $errs { ::practcl::log $logfile "###\n# ERROR\n###\n$item" ::practcl::log $logfile "###\n# TRACE\n###\n$trace" } ::practcl::log $logfile "*** DEBUG INFO ***" ::practcl::log $logfile $::DEBUG_INFO |
︙ | ︙ |
Changes to modules/practcl/build/class/object.tcl.
1 2 3 4 5 6 | ::oo::class create ::practcl::object { superclass ::practcl::metaclass constructor {parent args} { my variable links define set organs [$parent child organs] | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ### # 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 array set define $organs array set define [$parent child define] array set links {} if {[llength $args]==1 && [file exists [lindex $args 0]]} { my define set filename [lindex $args 0] ::practcl::product select [self] } elseif {[llength $args] == 1} { |
︙ | ︙ |
Changes to modules/practcl/build/class/product.tcl.
|
| | > > < | 1 2 3 4 5 6 7 8 9 10 11 | ### # A deliverable for the build system ### ::oo::class create ::practcl::product { method code {section body} { my variable code ::practcl::cputs code($section) $body } method Collate_Source CWD {} |
︙ | ︙ |
Changes to modules/practcl/build/class/project/baseclass.tcl.
︙ | ︙ | |||
120 121 122 123 124 125 126 127 128 129 130 131 132 133 | } $tkobj define set config_opts $tk_config_opts $tkobj compile } method child which { switch $which { organs { # A library can be a project, it can be a module. Any # subordinate modules will indicate their existance return [list project [self] module [self]] } } } | > | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | } $tkobj define set config_opts $tk_config_opts $tkobj compile } method child which { switch $which { delegate - organs { # A library can be a project, it can be a module. Any # subordinate modules will indicate their existance return [list project [self] module [self]] } } } |
︙ | ︙ |
Changes to modules/practcl/build/class/subproject/baseclass.tcl.
︙ | ︙ | |||
8 9 10 11 12 13 14 15 16 17 18 19 20 21 | method BuildDir {PWD} { return [my define get srcdir] } method child which { switch $which { organs { # A library can be a project, it can be a module. Any # subordinate modules will indicate their existance return [list project [self] module [self]] } } } | > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | method BuildDir {PWD} { return [my define get srcdir] } method child which { switch $which { delegate - organs { # A library can be a project, it can be a module. Any # subordinate modules will indicate their existance return [list project [self] module [self]] } } } |
︙ | ︙ |
Changes to modules/practcl/build/fileutil.tcl.
1 2 3 | ### # Bits stolen from fileutil ### | < < < | < < < < | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ### # Bits stolen from fileutil ### ### # grep ### proc ::practcl::grep {pattern {files {}}} { set result [list] if {[llength $files] == 0} { # read from stdin set lnum 0 while {[gets stdin line] >= 0} { incr lnum |
︙ | ︙ |
Added modules/practcl/build/footer.txt.
> > | 1 2 | [vset CATEGORY practcl] [include ../doctools2base/include/feedback.inc] |
Added modules/practcl/build/manual.txt.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | [comment {-*- %module% -*-}] [vset VERSION %version%] [manpage_begin practcl n [vset VERSION]] [keywords practcl] [copyright {2016-2018 Sean Woods <[email protected]>}] [moddesc {The The Proper Rational API for C to Tool Command Language Module}] [titledesc {The Practcl Module}] [category {TclOO}] [require TclOO 1.0] [require practcl [vset VERSION]] [description] The Practcl module is a tool for integrating large modules for C API Tcl code that requires custom Tcl types and TclOO objects. |
Changes to modules/practcl/pkgIndex.tcl.
1 | ### | | | | 1 2 3 4 | ### if {![package vsatisfies [package provide Tcl] 8.6]} {return} package ifneeded practcl 0.13 [list source [file join $dir practcl.tcl]] |
Changes to modules/practcl/practcl.man.
1 | [comment {-*- practcl -*-}] | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > | | > > > > > > > > < | > > | > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 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 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 | [comment {-*- practcl -*-}] [vset VERSION 0.13] [manpage_begin practcl n [vset VERSION]] [keywords practcl] [copyright {2016-2018 Sean Woods <[email protected]>}] [moddesc {The The Proper Rational API for C to Tool Command Language Module}] [titledesc {The Practcl Module}] [category {TclOO}] [require TclOO 1.0] [require practcl [vset VERSION]] [description] The Practcl module is a tool for integrating large modules for C API Tcl code that requires custom Tcl types and TclOO objects. [section {Commands}] [list_begin definitions] [call proc [cmd practcl::cat] [arg fname]] [call proc [cmd putb] [arg buffername] [opt "[arg args]"]] [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::grep] [arg pattern] [opt "[arg files] [const ""]"]] grep [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 clay::doctool}] [para] [class {Methods}] [list_begin definitions] [call method [cmd constructor]] [call method [cmd arglist] [arg arglist]] [call method [cmd comment] [arg block]] [call method [cmd keyword.Class] [arg resultvar] [arg commentblock] [arg name] [arg body]] Process an oo::objdefine call that modifies the class object itself [call method [cmd keyword.class] [arg resultvar] [arg commentblock] [arg name] [arg body]] [call method [cmd keyword.class_method] [arg resultvar] [arg commentblock] [arg name] [opt "[arg args]"]] [call method [cmd keyword.method] [arg resultvar] [arg commentblock] [arg name] [opt "[arg args]"]] [call method [cmd keyword.proc] [arg commentblock] [arg name] [arg arglist] [arg body]] [call method [cmd reset]] [call method [cmd section.command] [arg procinfo]] [call method [cmd section.class] [arg class_name] [arg class_info]] [call method [cmd manpage] [opt "[arg args]"]] [call method [cmd scan_text] [arg text]] [call method [cmd scan_file] [arg filename]] [list_end] [para] [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 make-compile]] [call method [cmd make-install] [arg DEST]] [call method [cmd build-compile-sources] [arg PROJECT] [arg COMPILE] [arg CPPCOMPILE] [arg INCLUDES]] [call method [cmd build-Makefile] [arg path] [arg PROJECT]] [call method [cmd build-library] [arg outfile] [arg PROJECT]] Produce a static or dynamic library [call method [cmd build-tclsh] [arg outfile] [arg PROJECT]] Produce a static executable [list_end] [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 output]] [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-typedef]] [call method [cmd generate-cfile-private-structure]] [call method [cmd generate-cfile-functions]] Generate code that provides subroutines called by Tcl API methods [call method [cmd generate-cfile-tclapi]] Generate code that provides implements Tcl API calls [call method [cmd generate-hfile-public-define]] [call method [cmd generate-hfile-public-macro]] [call method [cmd generate-hfile-public-typedef]] [call method [cmd generate-hfile-public-structure]] [call method [cmd generate-hfile-public-headers]] [call method [cmd generate-hfile-public-function]] [call method [cmd generate-hfile-public-includes]] [call method [cmd generate-hfile-public-verbatim]] [call method [cmd generate-loader-external]] [call method [cmd generate-loader-module]] [call method [cmd generate-stub-function]] [call method [cmd IncludeAdd] [arg headervar] [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 go]] [call method [cmd generate-decls] [arg pkgname] [arg path]] [call method [cmd implement] [arg path]] [call method [cmd generate-make] [arg path]] Backward compadible call [call method [cmd linktype]] [call method [cmd package-ifneeded] [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 Sandbox]] [call method [cmd SrcDir]] [call method [cmd ScmTag]] [call method [cmd ScmClone]] [call method [cmd ScmUnpack]] [call method [cmd ScmUpdate]] [call method [cmd Unpack]] [list_end] [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 child] [arg which]] [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-external] [arg configdict]] [call method [cmd linker-extra] [arg configdict]] [call method [cmd env-bootstrap]] Methods for packages/tools that can be downloaded possibly built and used internally by this Practcl process Load the facility into the interpreter [call method [cmd env-exec]] Return a file path that exec can call [call method [cmd env-install]] Install the tool into the local environment [call method [cmd env-load]] Do whatever is necessary to get the tool into the local environment [call method [cmd env-present]] Check if tool is available for load/already loaded [call method [cmd sources]] [call method [cmd update]] [call method [cmd unpack]] [list_end] [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 project-compile-products]] [call method [cmd ComputeInstall]] [call method [cmd go]] [call method [cmd linker-products] [arg configdict]] [call method [cmd project-static-packages]] [call method [cmd BuildDir] [arg PWD]] [call method [cmd compile]] [call method [cmd Configure]] [call method [cmd install] [arg DEST]] [list_end] [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 env-install]] [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.
1 2 3 4 5 | ### # Amalgamated package for practcl # Do not edit directly, tweak the source in src/ and rerun # build.tcl ### | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ### # Amalgamated package for practcl # Do not edit directly, tweak the source in src/ and rerun # build.tcl ### package require Tcl 8.6 package provide practcl 0.13 namespace eval ::practcl {} ### # START: httpwget/wget.tcl ### ### # Tool to download file from the web |
︙ | ︙ | |||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 | close $tmpchan } ### # END: httpwget/wget.tcl ### ### # START: setup.tcl ### ### # Practcl # An object oriented templating system for stamping out Tcl API calls to C ### | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | close $tmpchan } ### # END: httpwget/wget.tcl ### ### # START: clay/build/procs.tcl ### ### # Global utilities ### if {[info commands ::ladd] eq {}} { proc ladd {varname args} { upvar 1 $varname var if ![info exists var] { set var {} } foreach item $args { if {$item in $var} continue lappend var $item } return $var } } if {[info command ::ldelete] eq {}} { proc ::ldelete {varname args} { upvar 1 $varname var if ![info exists var] { return } foreach item [lsort -unique $args] { while {[set i [lsearch $var $item]]>=0} { set var [lreplace $var $i $i] } } return $var } } if {[info command ::lrandom] eq {}} { proc ::lrandom list { set len [llength $list] set idx [expr int(rand()*$len)] return [lindex $list $idx] } } if {[::info commands ::tcl::dict::getnull] eq {}} { proc ::tcl::dict::getnull {dictionary args} { if {[exists $dictionary {*}$args]} { get $dictionary {*}$args } } namespace ensemble configure dict -map [dict replace\ [namespace ensemble configure dict -map] getnull ::tcl::dict::getnull] } proc ::putb {buffername args} { upvar 1 $buffername buffer switch [llength $args] { 1 { append buffer [lindex $args 0] \n } 2 { append buffer [string map {*}$args] \n } default { error "usage: putb buffername ?map? string" } } } namespace eval ::clay {} set ::clay::trace 0 proc ::clay::ancestors args { set result {} set queue {} foreach class [lreverse $args] { lappend queue $class } # Rig things such that that the top superclasses # are evaluated first while {[llength $queue]} { set tqueue $queue set queue {} foreach qclass $tqueue { foreach aclass [::info class superclasses $qclass] { if { $aclass in $result } continue if { $aclass in $queue } continue lappend queue $aclass } } foreach item $tqueue { if { $item ni $result } { lappend result $item } } } return $result } proc ::clay::args_to_dict args { if {[llength $args]==1} { return [lindex $args 0] } return $args } proc ::clay::args_to_options args { set result {} foreach {var val} [args_to_dict {*}$args] { lappend result [string trim $var -:] $val } return $result } proc ::clay::dictmerge {varname args} { upvar 1 $varname result if {![info exists result]} { set result {} } switch [llength $args] { 0 { return } 1 { set result [_dictmerge $result [lindex $args 0]] return $result } 2 { lassign $args path value } default { # Merge b into a, and handle nested dicts appropriately set value [lindex $args end] set path [lrange $args 0 end-1] } } if {![dict exists $result {*}$path]} { dict set result {*}$path $value return $result } if {[string index [lindex $path end] end] ne "/"} { dict set result {*}$path $value return $result } ::dict for { k v } $value { # Element names that end in "/" are assumed to be branches if {[string index $k end] eq "/" && [::dict exists $result {*}$path $k]} { # key exists in a and b? let's see if both values are dicts # both are dicts, so merge the dicts set dvalue [::dict get $result {*}$path $k] if { [is_dict $dvalue] && [is_dict $v] } { ::dict set result {*}$path $k [_dictmerge $dvalue $v] } else { ::dict set result {*}$path $k $v } } else { ::dict set result {*}$path $k $v } } return $result } proc ::clay::_dictmerge {a b} { ::set result $a # Merge b into a, and handle nested dicts appropriately ::dict for { k v } $b { if {[string index $k end] ne "/"} { # Element names that do not end in "/" are assumed to be literals # or dict trees we intend to replace wholly ::dict set result $k $v } elseif { [::dict exists $result $k] } { # key exists in a and b? let's see if both values are dicts # both are dicts, so merge the dicts if { [is_dict [::dict get $result $k]] && [is_dict $v] } { ::dict set result $k [_dictmerge [::dict get $result $k] $v] } else { ::dict set result $k $v } } else { ::dict set result $k $v } } return $result } proc ::clay::dictputb {dict} { set result {} set level -1 _dictputb 0 $level result $dict return $result } proc ::clay::_dictputb {leaf level varname dict} { upvar 1 $varname result incr level foreach {field value} $dict { if {[string index $field end] eq "/"} { putb result "[string repeat " " $level]$field \{" _dictputb 0 $level result $value putb result "[string repeat " " $level]\}" } else { putb result "[string repeat " " $level][list $field $value]" } } } ### # topic: 4969d897a83d91a230a17f166dbcaede ### proc ::clay::dynamic_arguments {ensemble method arglist args} { set idx 0 set len [llength $args] if {$len > [llength $arglist]} { ### # Catch if the user supplies too many arguments ### set dargs 0 if {[lindex $arglist end] ni {args dictargs}} { return -code error -level 2 "Usage: $ensemble $method [string trim [dynamic_wrongargs_message $arglist]]" } } foreach argdef $arglist { if {$argdef eq "args"} { ### # Perform args processing in the style of tcl ### uplevel 1 [list set args [lrange $args $idx end]] break } if {$argdef eq "dictargs"} { ### # Perform args processing in the style of tcl ### uplevel 1 [list set args [lrange $args $idx end]] ### # Perform args processing in the style of clay ### set dictargs [::clay::args_to_options {*}[lrange $args $idx end]] uplevel 1 [list set dictargs $dictargs] break } if {$idx > $len} { ### # Catch if the user supplies too few arguments ### if {[llength $argdef]==1} { return -code error -level 2 "Usage: $ensemble $method [string trim [dynamic_wrongargs_message $arglist]]" } else { uplevel 1 [list set [lindex $argdef 0] [lindex $argdef 1]] } } else { uplevel 1 [list set [lindex $argdef 0] [lindex $args $idx]] } incr idx } } ### # topic: 53ab28ac5c6ee601fe1fe07b073be88e ### proc ::clay::dynamic_wrongargs_message {arglist} { set result "" set dargs 0 foreach argdef $arglist { if {$argdef in {args dictargs}} { set dargs 1 break } if {[llength $argdef]==1} { append result " $argdef" } else { append result " ?[lindex $argdef 0]?" } } if { $dargs } { append result " ?option value?..." } return $result } proc ::clay::is_dict { d } { # is it a dict, or can it be treated like one? if {[catch {::dict size $d} err]} { #::set ::errorInfo {} return 0 } return 1 } proc ::clay::is_null value { return [expr {$value in {{} NULL}}] } proc ::clay::leaf args { set marker [string index [lindex $args end] end] set result [path {*}${args}] if {$marker eq "/"} { return $result } return [list {*}[lrange $result 0 end-1] [string trim [string trim [lindex $result end]] /]] } proc ::clay::path args { set result {} foreach item $args { set item [string trim $item :./] foreach subitem [split $item /] { lappend result [string trim ${subitem}]/ } } return $result } proc ::clay::script_path {} { set path [file dirname [file join [pwd] [info script]]] return $path } proc ::clay::NSNormalize qualname { if {![string match ::* $qualname]} { set qualname ::clay::classes::$qualname } regsub -all {::+} $qualname "::" } proc ::clay::uuid_generate args { return [uuid::uuid generate] } namespace eval ::clay { variable option_class {} variable core_classes {::oo::class ::oo::object} } ### # END: clay/build/procs.tcl ### ### # START: clay/build/class.tcl ### oo::define oo::class { method clay {submethod args} { my variable clay if {![info exists clay]} { set clay {} } switch $submethod { ancestors { tailcall ::clay::ancestors [self] } exists { set path [::clay::leaf {*}$args] if {![info exists clay]} { return 0 } return [dict exists $clay {*}$path] } dump { return $clay } getnull - get { set path $args set leaf [expr {[string index [lindex $path end] end] ne "/"}] set clayorder [::clay::ancestors [self]] #puts [list [self] clay get {*}$path (leaf: $leaf)] if {$leaf} { #puts [list EXISTS: (clay) [dict exists $clay {*}$path]] if {[dict exists $clay {*}$path]} { return [dict get $clay {*}$path] } #puts [list Search in the in our list of classes for an answer] foreach class $clayorder { if {$class eq [self]} continue if {[$class clay exists {*}$path]} { set value [$class clay get {*}$path] return $value } } } else { set result {} # Leaf searches return one data field at a time # Search in our local dict # Search in the in our list of classes for an answer foreach class [lreverse $clayorder] { if {$class eq [self]} continue ::clay::dictmerge result [$class clay get {*}$path] } if {[dict exists $clay {*}$path]} { ::clay::dictmerge result [dict get $clay {*}$path] } return $result } } merge { foreach arg $args { ::clay::dictmerge clay {*}$arg } } search { foreach aclass [::clay::ancestors [self]] { if {[$aclass clay exists {*}$args]} { return [$aclass clay get {*}$args] } } } set { #puts [list [self] clay SET {*}$args] set value [lindex $args end] set path [::clay::leaf {*}[lrange $args 0 end-1]] ::clay::dictmerge clay {*}$path $value } default { dict $submethod clay {*}$args } } } } ### # END: clay/build/class.tcl ### ### # START: clay/build/object.tcl ### oo::define oo::object { ### # title: Provide access to clay data # format: markdown # description: # The *clay* method allows an object access # to a combination of its own clay data as # well as to that of its class ### method clay {submethod args} { my variable clay claycache clayorder config option_canonical if {![info exists clay]} {set clay {}} if {![info exists claycache]} {set claycache {}} if {![info exists config]} {set config {}} if {![info exists clayorder] || [llength $clayorder]==0} { set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] } switch $submethod { ancestors { return $clayorder } cget { # Leaf searches return one data field at a time # Search in our local dict if {[llength $args]==1} { set field [string trim [lindex $args 0] -:/] if {[info exists option_canonical($field)]} { set field $option_canonical($field) } if {[dict exists $config $field]} { return [dict get $config $field] } } if {[dict exists $clay {*}$args]} { return [dict get $clay {*}$args] } # Search in our local cache if {[dict exists $claycache {*}$args]} { return [dict get $claycache {*}$args] } # Search in the in our list of classes for an answer foreach class $clayorder { if {[$class clay exists {*}$args]} { set value [$class clay get {*}$args] dict set claycache {*}$args $value return $value } if {[$class clay exists const/ {*}$args]} { set value [$class clay get const/ {*}$args] dict set claycache {*}$args $value return $value } } return {} } delegate { if {![dict exists $clay delegate/ <class>]} { dict set clay delegate/ <class> [info object class [self]] } if {[llength $args]==0} { return [dict get $clay delegate/] } if {[llength $args]==1} { set stub <[string trim [lindex $args 0] <>]> if {![dict exists $clay delegate/ $stub]} { return {} } return [dict get $clay delegate/ $stub] } if {([llength $args] % 2)} { error "Usage: delegate OR delegate stub OR delegate stub OBJECT ?stub OBJECT? ..." } foreach {stub object} $args { set stub <[string trim $stub <>]> dict set clay delegate/ $stub $object oo::objdefine [self] forward ${stub} $object oo::objdefine [self] export ${stub} } } dump { # Do a full dump of clay data set result $clay # Search in the in our list of classes for an answer foreach class $clayorder { ::clay::dictmerge result [$class clay dump] } ::clay::dictmerge result $clay return $result } ensemble_map { set ensemble [lindex $args 0] my variable claycache set mensemble [string trim $ensemble :/]/ if {[dict exists $claycache method_ensemble/ $mensemble]} { return [dict get $claycache method_ensemble/ $mensemble] } set emap [my clay get method_ensemble/ $mensemble] dict set claycache method_ensemble/ $mensemble $emap return $emap } eval { set script [lindex $args 0] set buffer {} set thisline {} foreach line [split $script \n] { append thisline $line if {![info complete $thisline]} { append thisline \n continue } set thisline [string trim $thisline] if {[string index $thisline 0] eq "#"} continue if {[string length $thisline]==0} continue if {[lindex $thisline 0] eq "my"} { # Line already calls out "my", accept verbatim append buffer $thisline \n } elseif {[string range $thisline 0 2] eq "::"} { # Fully qualified commands accepted verbatim append buffer $thisline \n } elseif { append buffer "my $thisline" \n } set thisline {} } eval $buffer } evolve - initialize { my InitializePublic } exists { # Leaf searches return one data field at a time # Search in our local dict if {[dict exists $clay {*}$args]} { return 1 } # Search in our local cache if {[dict exists $claycache {*}$args]} { return 2 } set count 2 # Search in the in our list of classes for an answer foreach class $clayorder { incr count if {[$class clay exists {*}$args]} { return $count } } return 0 } flush { set claycache {} set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] } forward { oo::objdefine [self] forward {*}$args } getnull - get { set leaf [expr {[string index [lindex $args end] end] ne "/"}] #puts [list [self] clay get {*}$args (leaf: $leaf)] if {$leaf} { #puts [list EXISTS: (clay) [dict exists $clay {*}$args]] if {[dict exists $clay {*}$args]} { return [dict get $clay {*}$args] } # Search in our local cache #puts [list EXISTS: (claycache) [dict exists $claycache {*}$args]] if {[dict exists $claycache {*}$args]} { return [dict get $claycache {*}$args] } # Search in the in our list of classes for an answer foreach class $clayorder { if {[$class clay exists {*}$args]} { set value [$class clay get {*}$args] dict set claycache {*}$args $value return $value } } } else { set result {} # Leaf searches return one data field at a time # Search in our local dict # Search in the in our list of classes for an answer foreach class [lreverse $clayorder] { ::clay::dictmerge result [$class clay get {*}$args] } if {[dict exists $clay {*}$args]} { ::clay::dictmerge result [dict get $clay {*}$args] } return $result } } leaf { # Leaf searches return one data field at a time # Search in our local dict if {[dict exists $clay {*}$args]} { return [dict get $clay {*}$args] } # Search in our local cache if {[dict exists $claycache {*}$args]} { return [dict get $claycache {*}$args] } # Search in the in our list of classes for an answer foreach class $clayorder { if {[$class clay exists {*}$args]} { set value [$class clay get {*}$args] dict set claycache {*}$args $value return $value } } } merge { foreach arg $args { ::clay::dictmerge clay {*}$arg } } mixin { ### # Mix in the class ### set prior [info object mixins [self]] set newmixin {} foreach item $args { lappend newmixin ::[string trimleft $item :] } set newmap $args foreach class $prior { if {$class ni $newmixin} { set script [$class clay get mixin/ unmap-script] if {[string length $script]} { if {[catch $script err errdat]} { puts stderr "[self] MIXIN ERROR POPPING $class:\n[dict get $errdat -errorinfo]" } } } } ::oo::objdefine [self] mixin {*}$args ### # Build a compsite map of all ensembles defined by the object's current # class as well as all of the classes being mixed in ### my InitializePublic foreach class $newmixin { if {$class ni $prior} { set script [$class clay get mixin/ map-script] if {[string length $script]} { if {[catch $script err errdat]} { puts stderr "[self] MIXIN ERROR PUSHING $class:\n[dict get $errdat -errorinfo]" } } } } foreach class $newmixin { set script [$class clay search mixin/ react-script] if {[string length $script]} { if {[catch $script err errdat]} { puts stderr "[self] MIXIN ERROR PEEKING $class:\n[dict get $errdat -errorinfo]" } break } } } mixinmap { my variable clay if {![dict exists $clay mixin]} { dict set clay mixin {} } if {[llength $args]==0} { return [dict get $clay mixin] } elseif {[llength $args]==1} { return [dict getnull $clay mixin [lindex $args 0]] } else { foreach {slot classes} $args { dict set clay mixin $slot $classes } set claycache {} set classlist {} foreach {item class} [dict get $clay mixin] { if {$class ne {}} { lappend classlist $class } } my clay mixin {*}$classlist } } provenance { if {[dict exists $clay {*}$args]} { return self } foreach class $clayorder { if {[$class clay exists {*}$args]} { return $class } } return {} } replace { set clay [lindex $args 0] } source { source [lindex $args 0] } set { #puts [list [self] clay SET {*}$args] set claycache {} ::clay::dictmerge clay {*}$args } default { dict $submethod clay {*}$args } } } ### # React to a mixin ### method InitializePublic {} { my variable clayorder clay claycache config option_canonical set claycache {} set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] if {![info exists config]} { set config {} } foreach {var value} [my clay get variable/] { set var [string trim $var :/] if { $var in {clay} } continue my variable $var if {![info exists $var]} { if {$::clay::trace>2} {puts [list initialize variable $var $value]} set $var $value } } foreach {var value} [my clay get dict/] { set var [string trim $var :/] my variable $var if {![info exists $var]} { set $var {} } foreach {f v} $value { if {![dict exists ${var} $f]} { if {$::clay::trace>2} {puts [list initialize dict $var $f $v]} dict set ${var} $f $v } } } foreach {var value} [my clay get dict/] { set var [string trim $var :/] foreach {f v} [my clay get $var/] { if {![dict exists ${var} $f]} { if {$::clay::trace>2} {puts [list initialize dict (from const) $var $f $v]} dict set ${var} $f $v } } } foreach {var value} [my clay get array/] { set var [string trim $var :/] if { $var eq {clay} } continue my variable $var if {![info exists $var]} { array set $var {} } foreach {f v} $value { if {![array exists ${var}($f)]} { if {$::clay::trace>2} {puts [list initialize array $var\($f\) $v]} set ${var}($f) $v } } } foreach {var value} [my clay get array/] { set var [string trim $var :/] foreach {f v} [my clay get $var/] { if {![array exists ${var}($f)]} { if {$::clay::trace>2} {puts [list initialize array (from const) $var\($f\) $v]} set ${var}($f) $v } } } foreach {field info} [my clay get option/] { set field [string trim $field -/:] foreach alias [dict getnull $info aliases] { set option_canonical($alias) $field } if {[dict exists $config $field]} continue set getcmd [dict getnull $info default-command] if {$getcmd ne {}} { set value [{*}[string map [list %field% $field %self% [namespace which my]] $getcmd]] } else { set value [dict getnull $info default] } dict set config $field $value set setcmd [dict getnull $info set-command] if {$setcmd ne {}} { {*}[string map [list %field% [list $field] %value% [list $value] %self% [namespace which my]] $setcmd] } } } } ### # END: clay/build/object.tcl ### ### # START: setup.tcl ### ### # Practcl # An object oriented templating system for stamping out Tcl API calls to C ### |
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | } namespace eval ::practcl {} namespace eval ::practcl::OBJECT {} ### # END: setup.tcl ### ### # 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 ### | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | < | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 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 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 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 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 | } namespace eval ::practcl {} namespace eval ::practcl::OBJECT {} ### # END: setup.tcl ### ### # START: docbuild.tcl ### ### # Tool for build scripts to dynamically generate manual files from comments # in source code files ### namespace eval ::practcl {} proc ::practcl::cat fname { if {![file exists $fname]} { return } set fin [open $fname r] set data [read $fin] close $fin return $data } proc ::putb {buffername args} { upvar 1 $buffername buffer switch [llength $args] { 1 { append buffer [lindex $args 0] \n } 2 { append buffer [string map {*}$args] \n } default { error "usage: putb buffername ?map? string" } } } oo::class create ::clay::doctool { constructor {} { my variable coro set coro [info object namespace [self]]::coro oo::objdefine [self] forward coro $coro coroutine $coro {*}[namespace code {my reset}] } method arglist {arglist} { set result [dict create] foreach arg $arglist { set name [lindex $arg 0] dict set result $name positional 1 dict set result $name mandatory 1 if {$name in {args dictargs}} { switch [llength $arg] { 1 { dict set result $name mandatory 0 } 2 { dict for {optname optinfo} [lindex $arg 1] { set optname [string trim $optname -:] dict set result $optname {positional 1 mandatory 0} dict for {f v} $optinfo { dict set result $optname [string trim $f -:] $v } } } default { error "Bad argument" } } } else { switch [llength $arg] { 1 { dict set result $name mandatory 1 } 2 { dict set result $name mandatory 0 dict set result $name default [lindex $arg 1] } default { error "Bad argument" } } } } return $result } method comment block { 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 thisline {} continue } 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 { my keyword.method info $commentblock {*}[lrange $thisline 1 end-1] 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] } 0 { set arglist dictargs #set body [lindex $args 0] } default {error "could not interpret method $name {*}$args"} } if {![dict exists $info arglist]} { dict set info arglist [my arglist $arglist] } dict set result method [string trim $name :] $info } method keyword.proc {commentblock name arglist body} { set info [my comment $commentblock] if {![dict exists $info arglist]} { dict set info arglist [my arglist $arglist] } return $info } method reset {} { my variable info set info [dict create] yield [info coroutine] set thisline {} set commentblock {} set linec 0 while 1 { set line [yield] append thisline $line \n if {![info complete $thisline]} continue set thisline [string trim $thisline] if {[string index $thisline 0] eq "#"} { append commentblock [string trimleft $thisline #] \n set thisline {} continue } set cmd [string trim [lindex $thisline 0] ":"] switch $cmd { 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" } } tao::define - clay::define - tool::define { lassign $thisline tcmd name body my keyword.class info $commentblock $name $body set commentblock {} } oo::class { lassign $thisline tcmd mthd name body my keyword.class info $commentblock $name $body set commentblock {} } 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 {} putb result "\[section \{Commands\}\]" putb result {[list_begin definitions]} dict for {method minfo} $procinfo { putb result {} set line "\[call proc \[cmd $method\]" if {[dict exists $minfo arglist]} { dict for {argname arginfo} [dict get $minfo arglist] { set positional 1 set mandatory 1 dict with arginfo {} if {$mandatory==0} { append line " \[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 {} set header {} set footer {} dict with args {} putb result $header dict for {sec_type sec_info} $info { switch $sec_type { proc { putb result [my section.command $sec_info] } class { 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 } method scan_text {text} { my variable linecount coro set linecount 0 foreach line [split $text \n] { incr linecount $coro $line } } method scan_file {filename} { my variable linecount coro set fin [open $filename r] set linecount 0 while {[gets $fin line]>=0} { incr linecount $coro $line } close $fin } } ### # END: docbuild.tcl ### ### # 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 } ### |
︙ | ︙ | |||
197 198 199 200 201 202 203 204 205 206 207 208 209 210 | 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] | > > > > > > > > > > > > > > > | 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 | 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] |
︙ | ︙ | |||
223 224 225 226 227 228 229 | proc ::practcl::sort_dict list { set result {} foreach key [lsort -dictionary [dict keys $list]] { dict set result $key [dict get $list $key] } return $result } | < < < < | < < | | | 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 | 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 } |
︙ | ︙ | |||
802 803 804 805 806 807 808 | ### ### # START: fileutil.tcl ### ### # Bits stolen from fileutil ### | < < < | < < < < | | > > | 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 | ### ### # START: fileutil.tcl ### ### # Bits stolen from fileutil ### ### # grep ### proc ::practcl::grep {pattern {files {}}} { set result [list] if {[llength $files] == 0} { # read from stdin set lnum 0 while {[gets stdin line] >= 0} { incr lnum |
︙ | ︙ | |||
1311 1312 1313 1314 1315 1316 1317 | } default { array $submethod define {*}$args } } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 | } default { array $submethod define {*}$args } } } method graft args { return [my clay delegate {*}$args] } method initialize {} {} method link {command args} { my variable links |
︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 | foreach {s c} $mixinslot { if {$c eq {}} continue lappend mixins $c } oo::objdefine [self] mixin {*}$mixins } | | < < | < < < < < < < | 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 | foreach {s c} $mixinslot { if {$c eq {}} continue lappend mixins $c } oo::objdefine [self] mixin {*}$mixins } method organ args { return [my clay delegate {*}$args] } method script script { eval $script } method select {} { |
︙ | ︙ | |||
1574 1575 1576 1577 1578 1579 1580 | oo::class create ::practcl::toolset { ### # find or fake a key/value list describing this project ### method config.sh {} { return [my read_configuration] } | | | | | 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 | oo::class create ::practcl::toolset { ### # find or fake a key/value list describing this project ### method config.sh {} { return [my read_configuration] } method BuildDir {PWD} { set name [my define get name] set debug [my define get debug 0] if {[my <project> define get LOCAL 0]} { return [my define get builddir [file join $PWD local $name]] } if {$debug} { return [my define get builddir [file join $PWD debug $name]] } else { return [my define get builddir [file join $PWD pkg $name]] } } method MakeDir {srcdir} { return $srcdir } method read_configuration {} { my variable conf_result if {[info exists conf_result]} { return $conf_result } set result {} set name [my define get name] |
︙ | ︙ | |||
1700 1701 1702 1703 1704 1705 1706 | } set srcdir [my SourceRoot] set PWD [pwd] cd $srcdir ::practcl::dotclexec $critcl {*}$args cd $PWD } | | | 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 | } set srcdir [my SourceRoot] set PWD [pwd] cd $srcdir ::practcl::dotclexec $critcl {*}$args cd $PWD } method make-autodetect {} {} } oo::objdefine ::practcl::toolset { |
︙ | ︙ | |||
2487 2488 2489 2490 2491 2492 2493 | # MSVC always builds in the source directory method BuildDir {PWD} { set srcdir [my define get srcdir] return $srcdir } | | | | | 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 | # MSVC always builds in the source directory method BuildDir {PWD} { set srcdir [my define get srcdir] return $srcdir } # Do nothing method make-autodetect {} { } method make-clean {} { set PWD [pwd] set srcdir [my define get srcdir] cd $srcdir catch {::practcl::doexec nmake -f makefile.vc clean} cd $PWD } method make-compile {} { set srcdir [my define get srcdir] if {[my define get static 1]} { puts "BUILDING Static $name $srcdir" } else { puts "BUILDING Dynamic $name $srcdir" } |
︙ | ︙ | |||
2525 2526 2527 2528 2529 2530 2531 | cd [file join $srcdir win] ::practcl::doexec nmake -f makefile.vc INSTALLDIR=[my <project> define get installdir] {*}[my NmakeOpts] release } else { error "No make.tcl or makefile.vc found for project $name" } } } | | | 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 | cd [file join $srcdir win] ::practcl::doexec nmake -f makefile.vc INSTALLDIR=[my <project> define get installdir] {*}[my NmakeOpts] release } else { error "No make.tcl or makefile.vc found for project $name" } } } method make-install DEST { set PWD [pwd] set srcdir [my define get srcdir] cd $srcdir if {$DEST eq {}} { error "No destination given" } |
︙ | ︙ | |||
2554 2555 2556 2557 2558 2559 2560 | } else { puts "[self] VFS INSTALL $DEST" ::practcl::doexec nmake -f makefile.vc INSTALLDIR=$DEST {*}[my NmakeOpts] install } } cd $PWD } | | | | 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 | } else { puts "[self] VFS INSTALL $DEST" ::practcl::doexec nmake -f makefile.vc INSTALLDIR=$DEST {*}[my NmakeOpts] install } } cd $PWD } # Detect what directory contains the Makefile template method MakeDir {srcdir} { set localsrcdir $srcdir if {[file exists [file join $srcdir generic]]} { my define add include_dir [file join $srcdir generic] } if {[file exists [file join $srcdir win]]} { my define add include_dir [file join $srcdir win] } if {[file exists [file join $srcdir makefile.vc]]} { set localsrcdir [file join $srcdir win] } return $localsrcdir } method NmakeOpts {} { set opts {} set builddir [file normalize [my define get builddir]] if {[my <project> define exists tclsrcdir]} { ### # On Windows we are probably running under MSYS, which doesn't deal with |
︙ | ︙ | |||
2656 2657 2658 2659 2660 2661 2662 | if {$filename ne {} && ![file exists $filename]} { set needs_make 1 } } } return $needs_make } | | | | 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 | if {$filename ne {} && ![file exists $filename]} { set needs_make 1 } } } return $needs_make } method output {} { set result {} set filename [my define get filename] if {$filename ne {}} { lappend result $filename } foreach filename [my define get files] { if {$filename ne {}} { lappend result $filename } } return $result } method reset {} { my variable triggered domake needs_make set triggerd 0 set domake 0 set needs_make 0 } method triggers {} { my variable triggered domake define if {$triggered} { return $domake } set triggered 1 set make_objects [my <module> make objects] |
︙ | ︙ | |||
2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 | ### # 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] | > > > | | 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 | ### # 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 array set define $organs array set define [$parent child define] array set links {} if {[llength $args]==1 && [file exists [lindex $args 0]]} { my define set filename [lindex $args 0] ::practcl::product select [self] } elseif {[llength $args] == 1} { |
︙ | ︙ | |||
2779 2780 2781 2782 2783 2784 2785 | foreach {f v} $argdat { dict set cstruct $name $f $v } if {![dict exists $cstruct $name public]} { dict set cstruct $name public 1 } } | | | 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 | foreach {f v} $argdat { dict set cstruct $name $f $v } if {![dict exists $cstruct $name public]} { dict set cstruct $name public 1 } } method include header { my define add include $header } method include_dir args { my define add include_dir {*}$args } |
︙ | ︙ | |||
3362 3363 3364 3365 3366 3367 3368 | ### # END: class dynamic.tcl ### ### # START: class product.tcl ### | | > > < | 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 | ### # END: class dynamic.tcl ### ### # START: class product.tcl ### ### # A deliverable for the build system ### ::oo::class create ::practcl::product { method code {section body} { my variable code ::practcl::cputs code($section) $body } method Collate_Source CWD {} |
︙ | ︙ | |||
4053 4054 4055 4056 4057 4058 4059 | ### ::oo::class create ::practcl::module { superclass ::practcl::object ::practcl::product.dynamic method _MorphPatterns {} { return {{@name@} {::practcl::module.@name@} ::practcl::module} } | | | | | | 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 | ### ::oo::class create ::practcl::module { superclass ::practcl::object ::practcl::product.dynamic method _MorphPatterns {} { return {{@name@} {::practcl::module.@name@} ::practcl::module} } method add args { my variable links set object [::practcl::object new [self] {*}$args] foreach linktype [$object linktype] { lappend links($linktype) $object } return $object } method install-headers args {} ### # Target handling ### method make {command args} { my variable make_object if {![info exists make_object]} { set make_object {} |
︙ | ︙ | |||
4166 4167 4168 4169 4170 4171 4172 | } task - target - add { set name [lindex $args 0] set info [uplevel #0 [list subst [lindex $args 1]]] set body [lindex $args 2] | | | 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 | } task - target - add { set name [lindex $args 0] set info [uplevel #0 [list subst [lindex $args 1]]] set body [lindex $args 2] set nspace [namespace current] if {[dict exist $make_object $name]} { set obj [dict get $$make_object $name] } else { set obj [::practcl::make_obj new [self] $name $info $body] dict set make_object $name $obj dict set target_make $name 0 |
︙ | ︙ | |||
4190 4191 4192 4193 4194 4195 4196 | return $obj } todo { foreach {name obj} $make_object { if {[$obj do]} { lappend result $name } | | | > | 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 | return $obj } todo { foreach {name obj} $make_object { if {[$obj do]} { lappend result $name } } } do { global CWD SRCDIR project SANDBOX foreach {name obj} $make_object { if {[$obj do]} { eval [$obj define get action] } } } } } method child which { switch $which { delegate - organs { return [list project [my define get project] module [self]] } } } ### |
︙ | ︙ | |||
4382 4383 4384 4385 4386 4387 4388 | lappend errs [dict get $errdat -errorinfo] } else { lappend errs $errdat } } } if {[llength $errs]} { | | | 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 | lappend errs [dict get $errdat -errorinfo] } else { lappend errs $errdat } } } if {[llength $errs]} { set logfile [file join $::CWD practcl.log] ::practcl::log $logfile "*** ERRORS ***" foreach {item trace} $errs { ::practcl::log $logfile "###\n# ERROR\n###\n$item" ::practcl::log $logfile "###\n# TRACE\n###\n$trace" } ::practcl::log $logfile "*** DEBUG INFO ***" ::practcl::log $logfile $::DEBUG_INFO |
︙ | ︙ | |||
4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 | } $tkobj define set config_opts $tk_config_opts $tkobj compile } method child which { switch $which { organs { # A library can be a project, it can be a module. Any # subordinate modules will indicate their existance return [list project [self] module [self]] } } } | > | 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 | } $tkobj define set config_opts $tk_config_opts $tkobj compile } method child which { switch $which { delegate - organs { # A library can be a project, it can be a module. Any # subordinate modules will indicate their existance return [list project [self] module [self]] } } } |
︙ | ︙ | |||
5347 5348 5349 5350 5351 5352 5353 | scm None hash {} maxdate {} tags {} isodate {} } } | | | 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 | scm None hash {} maxdate {} tags {} isodate {} } } method DistroMixIn {} { my define set scm none } method Sandbox {} { if {[my define exists sandbox]} { return [my define get sandbox] |
︙ | ︙ | |||
5548 5549 5550 5551 5552 5553 5554 | set info [next] dict set info scm fossil foreach {field value} [::practcl::fossil_status [my define get srcdir]] { dict set info $field $value } return $info } | | | 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 | set info [next] dict set info scm fossil foreach {field value} [::practcl::fossil_status [my define get srcdir]] { dict set info $field $value } return $info } # Clone the source method ScmClone {} { set srcdir [my SrcDir] if {[file exists [file join $srcdir .fslckout]]} { return } if {[file exists [file join $srcdir _FOSSIL_]]} { |
︙ | ︙ | |||
5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 | method BuildDir {PWD} { return [my define get srcdir] } method child which { switch $which { organs { # A library can be a project, it can be a module. Any # subordinate modules will indicate their existance return [list project [self] module [self]] } } } | > | 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 | method BuildDir {PWD} { return [my define get srcdir] } method child which { switch $which { delegate - organs { # A library can be a project, it can be a module. Any # subordinate modules will indicate their existance return [list project [self] module [self]] } } } |
︙ | ︙ |
Changes to modules/pt/pkgIndex.tcl.
︙ | ︙ | |||
17 18 19 20 21 22 23 | package ifneeded pt::pe 1.0.2 [list source [file join $dir pt_pexpression.tcl]] package ifneeded pt::pe::op 1.0.1 [list source [file join $dir pt_pexpr_op.tcl]] # Parsing Expression Grammar support. package ifneeded pt::peg 1 [list source [file join $dir pt_pegrammar.tcl]] package ifneeded pt::peg::container 1 [list source [file join $dir pt_peg_container.tcl]] package ifneeded pt::peg::interp 1.0.1 [list source [file join $dir pt_peg_interp.tcl]] | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package ifneeded pt::pe 1.0.2 [list source [file join $dir pt_pexpression.tcl]] package ifneeded pt::pe::op 1.0.1 [list source [file join $dir pt_pexpr_op.tcl]] # Parsing Expression Grammar support. package ifneeded pt::peg 1 [list source [file join $dir pt_pegrammar.tcl]] package ifneeded pt::peg::container 1 [list source [file join $dir pt_peg_container.tcl]] package ifneeded pt::peg::interp 1.0.1 [list source [file join $dir pt_peg_interp.tcl]] package ifneeded pt::peg::op 1.1.0 [list source [file join $dir pt_peg_op.tcl]] package ifneeded pt::parse::peg 1.0.1 [list source [file join $dir pt_parse_peg.tcl]] # Export/import managers. Assumes an untrusted environment. package ifneeded pt::peg::export 1 [list source [file join $dir pt_peg_export.tcl]] package ifneeded pt::peg::import 1 [list source [file join $dir pt_peg_import.tcl]] |
︙ | ︙ |
Changes to modules/pt/pt_peg_op.man.
1 | [comment {-*- text -*- doctools manpage}] | | | 1 2 3 4 5 6 7 8 9 | [comment {-*- text -*- doctools manpage}] [vset VERSION 1.1.0] [manpage_begin pt_peg_op i [vset VERSION]] [include include/module.inc] [titledesc {Parser Tools PE Grammar Utility Operations}] [require pt::peg::op [opt [vset VERSION]]] [description] [include include/ref_intro.inc] |
︙ | ︙ |
Changes to modules/pt/pt_peg_op.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # -*- tcl -*- # Copyright (c) 2009-2018 Andreas Kupries <[email protected]> # Utility commands operating on parsing expressions. # # ## ### ##### ######## ############# ##################### ## Requirements package require Tcl 8.5 ; # Required runtime. package require pt::pe ; # PE basics package require pt::pe::op ; # PE transforms package require struct::set ; # Set operations (symbol sets) # # ## ### ##### ######## ############# ##################### ## namespace eval ::pt::peg::op { namespace export \ flatten called reachable realizable \ | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # -*- tcl -*- # Copyright (c) 2009-2018 Andreas Kupries <[email protected]> # Copyright (c) 2018 Stefan Sobernig <[email protected]> # Utility commands operating on parsing expressions. # # ## ### ##### ######## ############# ##################### ## Requirements package require Tcl 8.5 ; # Required runtime. package require pt::pe ; # PE basics package require pt::pe::op ; # PE transforms package require struct::set ; # Set operations (symbol sets) # # ## ### ##### ######## ############# ##################### ## namespace eval ::pt::peg::op { namespace export \ flatten called reachable realizable \ drop modeopt minimize dechain namespace ensemble create namespace eval ::pt::peg::op::drop { namespace export \ unreachable unrealizable |
︙ | ︙ | |||
58 59 60 61 62 63 64 | } return $dict } proc ::pt::peg::op::dechain {container} { | < < < < < < < < < < < < < < < < < < < < > > > > | < > | | | | | > | | < > > | | | > > | > | > | | > > | < > | > | > | < | | | > > | 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 | } return $dict } proc ::pt::peg::op::dechain {container} { set changed 1 while {$changed} { set chainPairs [dict create] set rules [$container rules] array set modes [$container modes] set changed 0 foreach {caller rule} $rules { lassign $rule op called if {$op ne "n"} continue dict set chainPairs $called $caller } set ends [struct::set difference \ [dict keys $chainPairs] \ [dict values $chainPairs]] if {[struct::set empty $ends]} { # stop, given a cycle break } set chainPairs [dict remove $chainPairs {*}$ends] set changed [dict size $chainPairs] if {$changed} { dict for {called caller} $chainPairs { if {$called in [$container nonterminals] && !(($modes($caller) ne "value") && (($modes($caller) ne "void") || ![info exists modes($called)] || ($modes($called) ne "void")))} { $container rule $caller [$container rule $called] } else { incr changed -1 } } } } return } # # ## ### ##### ######## ############# proc ::pt::peg::op::modeopt {container} { |
︙ | ︙ | |||
152 153 154 155 156 157 158 | } # Rule 2 set callmode [CallMode $caller($sym) mode] if {($callmode eq "void") && ($mode($sym) ne "void")} { | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | } # Rule 2 set callmode [CallMode $caller($sym) mode] if {($callmode eq "void") && ($mode($sym) ne "void")} { #puts (2)$sym set mode($sym) void # This change may change calling context and this call # mode of the symbols we call, so put them back up for # consideration. struct::set add changed $calls($sym) } |
︙ | ︙ | |||
186 187 188 189 190 191 192 193 194 | } } # # ## ### ##### ######## ############# proc ::pt::peg::op::minimize {container} { flatten $container drop unrealizable $container drop unreachable $container | > > < | | | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | } } # # ## ### ##### ######## ############# proc ::pt::peg::op::minimize {container} { flatten $container modeopt $container; # for dechaining dechain $container drop unrealizable $container drop unreachable $container modeopt $container; flatten $container return } # # ## ### ##### ######## ############# proc ::pt::peg::op::reachable {container} { |
︙ | ︙ | |||
370 371 372 373 374 375 376 | ## State / Configuration :: n/a namespace eval ::pt::peg::op {} # # ## ### ##### ######## ############# ##################### ## Ready | | | 367 368 369 370 371 372 373 374 375 | ## State / Configuration :: n/a namespace eval ::pt::peg::op {} # # ## ### ##### ######## ############# ##################### ## Ready package provide pt::peg::op 1.1.0 return |
Changes to modules/pt/tests/pt_peg_op.tests.
1 2 3 4 5 6 7 | # -*- tcl -*- # Testsuite for pt::peg::op. # [ok] drop unreachable # [ok] drop unrealizable # [ok] flatten # [ok] minimize | > | | | | | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # -*- tcl -*- # Testsuite for pt::peg::op. # Copyright (c) 2018 Stefan Sobernig <[email protected]> # [ok] drop unreachable # [ok] drop unrealizable # [ok] flatten # [ok] minimize # [ok] called # [ok] realizable # [ok] reachable # [ok] dechain # [ok] modeopt # ------------------------------------------------------------------------- # Basic syntax foreach op { called dechain |
︙ | ︙ | |||
51 52 53 54 55 56 57 | proc TestTransformation {op data setImpl} { # Convert operation and data table into series of test cases set debug 0 # Note, the `op` changes the container (here ::In) in-place. append bodyScript [list {*}::pt::peg::op::$op ::In] \; if {$debug} { | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | proc TestTransformation {op data setImpl} { # Convert operation and data table into series of test cases set debug 0 # Note, the `op` changes the container (here ::In) in-place. append bodyScript [list {*}::pt::peg::op::$op ::In] \; if {$debug} { append bodyScript "puts stderr \"ASIS \[::In serialize\]\"" \; append bodyScript "puts stderr \"TOBE \[::Expected serialize\]\"" \; } # After the op, when all is well, the content of ::In should be # the same as ::Expected. append bodyScript "pt::peg equal \[::In serialize\] \[::Expected serialize\]" \; set n 1 foreach {inStart inRulesSet outStart outRulesSet} [sl $data] { set testLabel "pt-peg-op-set:${setImpl}-[join $op -]-$n" if {$debug} { puts stderr >>>>$testLabel<<<< } test $testLabel "OP '$op' vs. expected" -setup { pt::peg::container ::In deserialize [g $inStart $inRulesSet] pt::peg::container ::Expected deserialize [g $outStart $outRulesSet] } -body $bodyScript -result 1 -cleanup { ::In destroy ::Expected destroy } incr n } } # ------------------------------------------------------------------------- # op: called set n 0 foreach {inStart inRulesSet expectedSym} [sl { # --- epsilon {} {{} {}} # --- {n S} { S {is {x {t A} {* {n SYM}} {t B} {n OTHER} {n SYM}} mode value} A {is {n A} mode value} } {{} S A A S {SYM OTHER}} # --- {n S} { S {is {x {t A} {t B}} mode value} A {is {t a} mode value} B {is {t b} mode value} } {{} S A {} B {} S {}} # --- {n S} { S {is {epsilon} mode value} } {{} S S {}} }] { test pt-peg-op-set:${setimpl}-called.$n {op called} -setup { pt::peg::container ::In deserialize [g $inStart $inRulesSet] } -body { set r [pt::peg::op called ::In] dict filter $r script {key val} { ::tcl::mathop::in $key [lsort [dict keys $r]] } } -cleanup { ::In destroy } -result $expectedSym incr n } unset n # ------------------------------------------------------------------------- # op: flatten TestTransformation flatten { # --- stays as-is #1 epsilon {} |
︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 136 137 138 139 140 | A {is {n A} mode value} } {n S} { S {is {/ {n A} {n A} {n A}} mode value} A {is {n A} mode value} } } $setimpl # ------------------------------------------------------------------------- # op: drop unrealizable TestTransformation "drop unrealizable" { # (1) stays as-is epsilon {} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | A {is {n A} mode value} } {n S} { S {is {/ {n A} {n A} {n A}} mode value} A {is {n A} mode value} } } $setimpl # ------------------------------------------------------------------------- # op: realizable set n 0 foreach {inStart inRulesSet expectedSym} [sl { # --- just start expression epsilon {} {{}} # -- all realizable, incl. start expression {n S} { S {is {n X} mode value} X {is {t x} mode leaf} } {{} S X} # -- not even start expression {n S} { S {is {n X} mode value} X {is {n X} mode value} } {} # -- not even start expression {n S} { S {is {n X} mode value} X {is {n X} mode value} } {} # -- X is unrealizable {n S} { S {is {? {n X}} mode value} X {is {n X} mode value} } {{} S} # -- X is unrealizable {n S} { S {is {/ {n X} {t y}} mode value} X {is {n X} mode value} } {{} S} # -- X <- 'A' 'B' X / 'C' X 'A'; X is unrealizable {n S} { S {is {/ {n X} {t y}} mode value} X {is {/ {x {t A} {t B} {n X}} {x {t C} {n X} {t A}}} mode value} } {{} S} # -- X <- 'A' 'B' X / 'C' X 'A' / 'x'; X *is* realizable {n S} { S {is {/ {n X} {t y}} mode value} X {is {/ {x {t A} {t B} {n X}} {x {t C} {n X} {t A}} {t x}} mode value} } {{} S X} # -- E is unrealizable {n S} { S {is {/ {x {n B} {t b}} {x {n C} {t c}} {x {n E} {t e}}} mode value} B {is {/ {x {n B} {t b}} {t b}} mode value} C {is {/ {x {n C} {t c}} {t c}} mode value} E {is {x {n E} {t e}} mode value} } {{} B C S} # -- S remains realizable (*) {n S} { S {is {* {n X}} mode value} X {is {n X} mode value} } {{} S} }] { test pt-peg-op-set:${setimpl}-realizable.$n {op realizable} -setup { pt::peg::container ::In deserialize [g $inStart $inRulesSet] } -body { lsort [pt::peg::op realizable ::In] } -cleanup { ::In destroy } -result $expectedSym incr n } unset n # ------------------------------------------------------------------------- # op: drop unrealizable TestTransformation "drop unrealizable" { # (1) stays as-is epsilon {} |
︙ | ︙ | |||
173 174 175 176 177 178 179 180 | X {is {n X} mode value} } {n S} { S {is {/ {t y}} mode value} } } $setimpl # ------------------------------------------------------------------------- | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | X {is {n X} mode value} } {n S} { S {is {/ {t y}} mode value} } } $setimpl # ------------------------------------------------------------------------- # op: reachable set n 0 foreach {inStart inRulesSet expectedSym} [sl { # --- none epsilon {} {} # -- D is not reachable {n S} { S {is {/ {x {n B} {t b}} {x {n C} {t c}} {x {n E} {t e}}} mode value} B {is {/ {x {n B} {t b}} {t b}} mode value} C {is {/ {x {n C} {t c}} {t c}} mode value} D {is {/ {x {n B} {t d}} {x {n C} {t d}} {t d}} mode value} E {is {x {n E} {t e}} mode value} } {B C E S} # -- all reachable {n S} { S {is {/ {x {n A} {n B}} {t a}} mode value} A {is {x {t a} {n A}} mode value} B {is {t a} mode leaf} } {A B S} }] { test pt-peg-op-set:${setimpl}-reachable.$n {op reachable} -setup { pt::peg::container ::In deserialize [g $inStart $inRulesSet] } -body { lsort [pt::peg::op reachable ::In] } -cleanup { ::In destroy } -result $expectedSym incr n } unset n # ------------------------------------------------------------------------- # op: drop unreachable TestTransformation "drop unreachable" { # (1) stays as-is epsilon {} epsilon {} # S <-- a; A <-- a ==> S <-- a (A not reachable, dropped) {n S} { |
︙ | ︙ | |||
198 199 200 201 202 203 204 205 206 207 208 209 210 211 | A {is {n B} mode void} B {is {t a} mode void} } {n S} { S {is {t a} mode leaf} } } $setimpl # ------------------------------------------------------------------------- # op: minimize TestTransformation minimize { # --- stays as-is epsilon {} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | A {is {n B} mode void} B {is {t a} mode void} } {n S} { S {is {t a} mode leaf} } } $setimpl # ------------------------------------------------------------------------- # op: dechain TestTransformation dechain { # --- stays as-is epsilon {} epsilon {} {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {t b} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {t b} mode value} } # --- basic chain: A <- B <- C (leaf) <- c |> A <- C (leaf) <- c {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {t c} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {t c} mode value} } # --- longer chain {n S} { S {is {x {n A} {t s}} mode value} E {is {t e} mode leaf} A {is {n B} mode value} D {is {n E} mode value} B {is {n C} mode value} C {is {n D} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n E} mode value} B {is {n D} mode value} C {is {n E} mode value} D {is {n E} mode value} E {is {t e} mode leaf} } # --- basic cycle: A <- B <- A {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n A} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n A} mode value} } # --- basic (indirect) cycle: A <- B <- C <- A {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {n A} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {n A} mode value} } # --- basic chain plus renaming for self-recursive leaves {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {x {n C} {t c}} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {x {n C} {t c}} mode value} } # {n S} { # S {is {x {n A} {t s}} mode value} # A {is {x {n A} {t c}} mode value} # B {is {x {n B} {t c}} mode value} # C {is {x {n C} {t c}} mode value} # } # --- start expression: {} <- Z <- S <- s |> {} <- Z <- s {n Z} { Z {is {n S} mode value} S {is {t s} mode value} } {n Z} { Z {is {n S} mode value} S {is {t s} mode value} } # --- TODO: start expression: {} <- Z <- S (leaf) <- s |> {} <- S <- s # {n Z} { # Z {is {n S} mode value} # S {is {t s} mode value} # } # {n S} { # S {is {t s} mode value} # } # --- broken chain #1 (undefined leaves?) {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} } # --- broken chain #2 (undefined leaves?) {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} B {is {n C} mode value} } # --- intermittents {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {x {n X} {t c}} mode value} X {is {n Y} mode value} Y {is {n Z} mode value} Z {is {x {n Z} {t z}} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {x {n X} {t c}} mode value} X {is {n Z} mode value} Y {is {n Z} mode value} Z {is {x {n Z} {t z}} mode value} } # {n S} { # S {is {x {n A} {t s}} mode value} # A {is {x {n X} {t c}} mode value} # B {is {x {n X} {t c}} mode value} # C {is {x {n X} {t c}} mode value} # X {is {x {n X} {t z}} mode value} # Y {is {x {n Y} {t z}} mode value} # Z {is {x {n Z} {t z}} mode value} # } # --- incompat modes #1a {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode void} B {is {n C} mode void} C {is {t c} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode void} B {is {n C} mode void} C {is {t c} mode value} } # --- incompat modes #1b {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode void} B {is {n C} mode value} C {is {t c} mode value} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode void} B {is {n C} mode value} C {is {t c} mode value} } # X <- Z # # X Z dechain notes # value value| yes | value is passed {n S} { S {is {n X} mode value} X {is {n Z} mode value} Z {is {t z} mode value} } {n S} { S {is {n Z} mode value} X {is {n Z} mode value} Z {is {t z} mode value} } # X Z dechain notes # leaf value| no | generated value was discarded, inlined doesn't. Z may be implied void {n S} { S {is {n X} mode leaf} X {is {n Z} mode value} Z {is {t z} mode value} } {n S} { S {is {n X} mode leaf} X {is {n Z} mode value} Z {is {t z} mode value} } # value leaf | yes | value is passed {n S} { S {is {n X} mode value} X {is {n Z} mode leaf} Z {is {t z} mode value} } {n S} { S {is {n Z} mode value} X {is {n Z} mode leaf} Z {is {t z} mode value} } # value void | yes | X is implied void {n S} { S {is {n X} mode value} X {is {n Z} mode void} Z {is {t z} mode value} } {n S} { S {is {n Z} mode value} X {is {n Z} mode void} Z {is {t z} mode value} } # leaf leaf | no | s.a. {n S} { S {is {n X} mode leaf} X {is {n Z} mode leaf} Z {is {t z} mode value} } {n S} { S {is {n X} mode leaf} X {is {n Z} mode leaf} Z {is {t z} mode value} } # leaf void | no | s.a. {n S} { S {is {n X} mode leaf} X {is {n Z} mode void} Z {is {t z} mode value} } {n S} { S {is {n X} mode leaf} X {is {n Z} mode void} Z {is {t z} mode value} } # void value| no | X drops value, inline doesn't {n S} { S {is {n X} mode void} X {is {n Z} mode value} Z {is {t z} mode value} } {n S} { S {is {n X} mode void} X {is {n Z} mode value} Z {is {t z} mode value} } # void leaf | no | s.a. {n S} { S {is {n X} mode void} X {is {n Z} mode leaf} Z {is {t z} mode value} } {n S} { S {is {n X} mode void} X {is {n Z} mode leaf} Z {is {t z} mode value} } # void void | yes | {n S} { S {is {n X} mode void} X {is {n Z} mode void} Z {is {t z} mode value} } {n S} { S {is {n Z} mode void} X {is {n Z} mode void} Z {is {t z} mode value} } {n S} { S {is {n S} mode value} } {n S} { S {is {n S} mode value} } } $setimpl # ------------------------------------------------------------------------- # op: modeopt TestTransformation modeopt { # --- stays as-is epsilon {} epsilon {} # --- cycle # S <-- A; A <-- A {n S} { S {is {n A} mode value} A {is {n A} mode value} } {n S} { S {is {n A} mode value} A {is {n A} mode value} } # -- undefined (deferred) symbol: B {n S} { S {is {n A} mode value} A {is {n B} mode value} } {n S} { S {is {n A} mode value} A {is {n B} mode value} } # --- rule 1 {n S} { S {is {n A} mode value} A {is {t A} mode value} } {n S} { S {is {n A} mode value} A {is {t A} mode leaf} } # --- rule 1 {n S} { S {is {n A} mode value} A {is {x {t A} {n B}} mode value} B {is {t b} mode value} } {n S} { S {is {n A} mode value} A {is {x {t A} {n B}} mode value} B {is {t b} mode leaf} } # --- rule 2 (no opt) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode value} B {is {n C} mode value} C {is {t c} mode leaf} } # --- rule 2 (void) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode void} B {is {n C} mode void} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode void} B {is {n C} mode void} C {is {t c} mode void} } # --- rule 2 (leaf) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode leaf} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode leaf} C {is {t c} mode void} } # --- rule 2 (mixed) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode void} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode void} C {is {t c} mode void} } # --- rule 2 (mixed, no opt) {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode value} C {is {t c} mode leaf} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode value} C {is {t c} mode leaf} } # --- rule 1: applies, rule 2: n/a {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode value} C {is {t c} mode value} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode value} C {is {t c} mode leaf} } # --- rule 1: applies, rule 2: applies {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode leaf} C {is {t c} mode value} } {n S} { S {is {x {n A} {n B}} mode value} A {is {n C} mode leaf} B {is {n C} mode leaf} C {is {t c} mode void} } } $setimpl # ------------------------------------------------------------------------- # op: minimize TestTransformation minimize { # --- stays as-is epsilon {} |
︙ | ︙ | |||
232 233 234 235 236 237 238 239 240 241 242 243 244 | S {is {/ {x {n A} {n B}} {t a}} mode value} A {is {x {t a} {n A}} mode value} B {is {t a} mode leaf} } {n S} { S {is {t a} mode leaf} } } $setimpl # ------------------------------------------------------------------------- rename sl {} rename g {} rename TestTransformation {} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | S {is {/ {x {n A} {n B}} {t a}} mode value} A {is {x {t a} {n A}} mode value} B {is {t a} mode leaf} } {n S} { S {is {t a} mode leaf} } # --- direct cycle {n A} { A {is {n A} mode value} } epsilon {} # --- indirect cycle {n A} { A {is {n B} mode value} B {is {n C} mode value} C {is {n A} mode value} } epsilon {} # --- dechaining creates unreachable and unrealisable rules; here: B, Y {n S} { S {is {x {n A} {t s}} mode value} A {is {n B} mode value} B {is {n C} mode value} C {is {x {n X} {t c}} mode value} X {is {n Y} mode value} Y {is {n Z} mode value} Z {is {x {t z}} mode leaf} } {n S} { S {is {x {n A} {t s}} mode value} A {is {n C} mode value} C {is {x {n X} {t c}} mode value} X {is {n Z} mode value} Z {is {t z} mode leaf} } # {n S} { # S {is {x {n A} {t s}} mode value} # A {is {x {n X} {t c}} mode value} # X {is {t z} mode leaf} # } } $setimpl # ------------------------------------------------------------------------- rename sl {} rename g {} rename TestTransformation {} |
Changes to modules/smtpd/smtpd.man.
︙ | ︙ | |||
218 219 220 221 222 223 224 | [def "[cmd validate_recipient] callback"] The validate_recipient callback is similar to the validate_sender callback and permits you to verify a local mailbox and accept mail for a local user address during RCPT command handling. To reject mail, throw an error as above. The error message is ignored. | | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | [def "[cmd validate_recipient] callback"] The validate_recipient callback is similar to the validate_sender callback and permits you to verify a local mailbox and accept mail for a local user address during RCPT command handling. To reject mail, throw an error as above. The error message is ignored. [def "[cmd deliverMIME] callback"] The deliverMIME callback is called once a mail message has been successfully passed to the server. A mime token is constructed from the sender, recipients and data and the users procedure it called with this single argument. When the call returns, the mime token is cleaned up so if the user wishes to preserve the data she must make a copy. |
︙ | ︙ |
Changes to modules/stooop/switched.man.
︙ | ︙ | |||
261 262 263 264 265 266 267 | the validity of the value passed to the [method set-[option option]] procedure, which should throw an error (for example by using the Tcl error command) if the value is invalid. [para] The switched layer also keeps track of the options current values, so that a [method set-[option option]] procedure is called only when the corresponding option value passed as parameter is | | | | | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | the validity of the value passed to the [method set-[option option]] procedure, which should throw an error (for example by using the Tcl error command) if the value is invalid. [para] The switched layer also keeps track of the options current values, so that a [method set-[option option]] procedure is called only when the corresponding option value passed as parameter is different from the current value (see [var -option] data members description). [def [var -option]] [para] The [var -option] data member is an options current value. There is one for each option listed in the options procedure. It is a read-only value which the switched layer checks against when an option is changed. It is rarely used at the layer derived from switched, except in the few cases, such as in the following example: |
︙ | ︙ | |||
297 298 299 300 301 302 303 | } }] [para] In this case, the manufacturer's name is stored at the switched layer level (this is why the set-manufacturer procedure has nothing to do) and later retrieved in the printData procedure. | | | | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | } }] [para] In this case, the manufacturer's name is stored at the switched layer level (this is why the set-manufacturer procedure has nothing to do) and later retrieved in the printData procedure. [def [var complete]] [para] The [var complete] data member (not to be confused with the [method complete] procedure) is a boolean. Its initial value is [const false] and it is set to [const true] at the very end of the switched [method complete] procedure. It becomes useful when some options should be set at construction time only and not dynamically, as the following example shows: |
︙ | ︙ |
Changes to modules/tepam/tepam_doc_gen.man.
︙ | ︙ | |||
223 224 225 226 227 228 229 | Generates the part of the command line or the synopsis that is specific to an argument. The generated string has to indicate if an argument is optional, named and if it is a flag. [para] The following parameters are provided to this procedure: [list_begin definitions] [def [arg "Name"]] Name of the argument [def [arg "IsOptional"]] | | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | Generates the part of the command line or the synopsis that is specific to an argument. The generated string has to indicate if an argument is optional, named and if it is a flag. [para] The following parameters are provided to this procedure: [list_begin definitions] [def [arg "Name"]] Name of the argument [def [arg "IsOptional"]] If true (=[const 1]) the argument is optional which should be indicated by the generated string (for example by putting the argument into brackets {[lb][rb]} or into question marks '?'): [example_begin]gen(TXT,ArgumentString) mtype 1 0 string -> [emph {"[mtype]"}][example_end] [def [arg "IsNamed"]] If true (=[const 1]) an argument is a named argument (option). The generated string should in this case contain the argument/option name, followed by the argument itself: [example_begin]gen(TXT,ArgumentString) mtype 0 1 string -> [emph {"-mtype <mtype>"}][example_end] Named arguments can also be optional: [example_begin]gen(TXT,ArgumentString) mtype 1 1 string -> [emph {"[-mtype <mtype>]"}][example_end] [def [arg "Type"]] |
︙ | ︙ |
Changes to modules/tepam/tepam_procedure.man.
︙ | ︙ | |||
772 773 774 775 776 777 778 | The name of the first unnamed argument has therefore not to start with the '-' character. The unnamed argument is otherwise considered as name of another named argument. This is especially important if the first unnamed argument is given by a variable that can contain any character strings: [example_begin]my_proc [cmd {-n1 N1 -n2 N2 "->" "<-"}] [emph {-> my_proc: Argument '->' not known}] set U1 "->" | | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 | The name of the first unnamed argument has therefore not to start with the '-' character. The unnamed argument is otherwise considered as name of another named argument. This is especially important if the first unnamed argument is given by a variable that can contain any character strings: [example_begin]my_proc [cmd {-n1 N1 -n2 N2 "->" "<-"}] [emph {-> my_proc: Argument '->' not known}] set U1 "->" my_proc [cmd {-n1 N1 -n2 N2 $U1 U2}] my_proc: Argument '->' not known[example_end] The '--' flag allows separating unambiguously the unnamed arguments from the named arguments. All data after the '--' flag will be considered as unnamed argument: [example_begin]my_proc [cmd {-n1 N1 -n2 N2 -- "->" "<-"}] [emph {-> n1:'N1', n2:'N2', u1:'->', u2:'<-'}] |
︙ | ︙ |
Changes to modules/textutil/adjust.man.
︙ | ︙ | |||
125 126 127 128 129 130 131 | [opt_def -length [arg integer]] Set the length of the [emph logical] line in the string to [arg integer]. [arg integer] must be a positive integer value. Defaults to [const 72]. | | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | [opt_def -length [arg integer]] Set the length of the [emph logical] line in the string to [arg integer]. [arg integer] must be a positive integer value. Defaults to [const 72]. [opt_def -strictlength [arg boolean]] If set to [const false] (default), a line can exceed the specified [option -length] if a single word is longer than [option -length]. If set to [const true], words that are longer than [option -length] are split so that no line exceeds the specified [option -length]. [list_end] |
︙ | ︙ |
Changes to modules/tool/build/option.tcl.
︙ | ︙ |
Changes to modules/tool/build/organ.tcl.
︙ | ︙ |
Changes to modules/tool/build/pipeline.tcl.
︙ | ︙ |
Changes to modules/tool/build/script.tcl.
︙ | ︙ |
Changes to modules/tool/module.shed.
︙ | ︙ |
Changes to modules/tool/tool.md.
︙ | ︙ |
Changes to modules/tool/tool_dict_ensemble.man.
︙ | ︙ | |||
11 12 13 14 15 16 17 | [description] [para] The [cmd dict_ensemble] command is a keyword added by [package tool]. It defines a public variable (stored as a dict), and an access function to manipulated and access the values stored in that dict. [list_begin definitions] | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | [description] [para] The [cmd dict_ensemble] command is a keyword added by [package tool]. It defines a public variable (stored as a dict), and an access function to manipulated and access the values stored in that dict. [list_begin definitions] [call [emph object] [arg ensemble] [cmd add] [arg field] [arg value] [arg {value ...}]] Adds elements to a list maintained with the [arg field] leaf of the dict maintained my this ensemble. Declares a variable [arg name] which will be initialized as an array, populated with [arg contents] for objects of this class, as well as any objects for classes which are descendents of this class. |
︙ | ︙ |
Changes to modules/uuid/pkgIndex.tcl.
1 | if {![package vsatisfies [package provide Tcl] 8.5]} {return} | | | 1 2 | if {![package vsatisfies [package provide Tcl] 8.5]} {return} package ifneeded uuid 1.0.7 [list source [file join $dir uuid.tcl]] |
Changes to modules/uuid/uuid.tcl.
︙ | ︙ | |||
44 45 46 47 48 49 50 | lappend machinfo [array get ::tcl_platform] ### # If we have /dev/urandom just stream 128 bits from that ### if {[file exists /dev/urandom]} { set fin [open /dev/urandom r] | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | lappend machinfo [array get ::tcl_platform] ### # If we have /dev/urandom just stream 128 bits from that ### if {[file exists /dev/urandom]} { set fin [open /dev/urandom r] binary scan [read $fin 128] H* machinfo close $fin } elseif {[catch {package require nettool}]} { # More spatial information -- better than hostname. # bug 1150714: opening a server socket may raise a warning messagebox # with WinXP firewall, using ipconfig will return all IP addresses # including ipv6 ones if available. ipconfig is OK on win98+ if {[string equal $::tcl_platform(platform) "windows"]} { |
︙ | ︙ | |||
232 233 234 235 236 237 238 | variable e {} foreach e {critcl} { if {[LoadAccelerator $e]} break } unset e } | | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | variable e {} foreach e {critcl} { if {[LoadAccelerator $e]} break } unset e } package provide uuid 1.0.7 # ------------------------------------------------------------------------- # Local variables: # mode: tcl # indent-tabs-mode: nil # End: |
Changes to modules/uuid/uuid.test.
1 2 3 4 5 6 7 8 9 10 11 | # uuid.test: tests for the uuid package -*- tcl -*- # # $Id: uuid.test,v 1.6 2006/10/09 21:41:42 andreas_kupries Exp $ # ------------------------------------------------------------------------- source [file join \ [file dirname [file dirname [file join [pwd] [info script]]]] \ devtools testutilities.tcl] testsNeedTcl 8.5 | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # uuid.test: tests for the uuid package -*- tcl -*- # # $Id: uuid.test,v 1.6 2006/10/09 21:41:42 andreas_kupries Exp $ # ------------------------------------------------------------------------- source [file join \ [file dirname [file dirname [file join [pwd] [info script]]]] \ devtools testutilities.tcl] testsNeedTcl 8.5 testsNeedTcltest 2.0 testing { useLocal uuid.tcl uuid } # ------------------------------------------------------------------------- # Handle multiple implementation testing |
︙ | ︙ | |||
57 58 59 60 61 62 63 | foreach impl [implementations] { select_implementation $impl test uuid-1.0-$impl "uuid requires args" { list [catch {uuid::uuid} msg] } {1} | | | | | | 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 | foreach impl [implementations] { select_implementation $impl test uuid-1.0-$impl "uuid requires args" { list [catch {uuid::uuid} msg] } {1} test uuid-1.1-$impl "uuid generate should create a 36 char string uuid" { list [catch {string length [uuid::uuid generate]} msg] $msg } {0 36} test uuid-1.2-$impl "uuid comparison of uuid with self should be true" { list [catch { set a [uuid::uuid generate] uuid::uuid equal $a $a } msg] $msg } {0 1} test uuid-1.3-$impl "uuid comparison of two different\ uuids should be false" { list [catch { set a [uuid::uuid generate] set b [uuid::uuid generate] uuid::uuid equal $a $b } msg] $msg } {0 0} reset_implementation } # ------------------------------------------------------------------------- testsuiteCleanup # ------------------------------------------------------------------------- # Local Variables: # mode: tcl # indent-tabs-mode: nil # End: |
Changes to modules/websocket/websocket.man.
︙ | ︙ | |||
201 202 203 204 205 206 207 | identifier fo an HTTP server that is capable of doing WebSockets. Paths onto which this server will listen for incoming connections should be declared using [cmd ::websocket::live]. [call [cmd ::websocket::live] [arg sock] [arg path] [arg cb] [opt [arg proto]]] This procedure registers callbacks that will be performed on a | | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | identifier fo an HTTP server that is capable of doing WebSockets. Paths onto which this server will listen for incoming connections should be declared using [cmd ::websocket::live]. [call [cmd ::websocket::live] [arg sock] [arg path] [arg cb] [opt [arg proto]]] This procedure registers callbacks that will be performed on a WebSocket compliant server registered with [cmd ::websocket::server] whenever a client connects to a matching path and protocol. [arg sock] is the listening socket of the websocket compliant server declared using [cmd ::websocket::server]. [arg path] is a glob-style path to match in client request, whenever this will occur. [arg cb] is the command to callback (see Callbacks). [arg proto] is a glob-style protocol name matcher. |
︙ | ︙ |
Changes to support/devel/sak/doc/kwic.txt.
︙ | ︙ | |||
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 | [manpage modules/math/interpolate.man math::interpolate] [manpage modules/math/linalg.man math::linearalgebra] [manpage modules/math/optimize.man math::optimize] [manpage modules/math/pca.man math::PCA] [manpage modules/math/polynomials.man math::polynomials] [manpage modules/math/rational_funcs.man math::rationalfunctions] [manpage modules/math/special.man math::special] [manpage modules/simulation/annealing.man simulation::annealing] [manpage modules/simulation/montecarlo.man simulation::montecarlo] [manpage modules/simulation/simulation_random.man simulation::random] [key mathematics] [manpage modules/math/fourier.man math::fourier] [manpage modules/math/statistics.man math::statistics] [key matrices] | > | 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 | [manpage modules/math/interpolate.man math::interpolate] [manpage modules/math/linalg.man math::linearalgebra] [manpage modules/math/optimize.man math::optimize] [manpage modules/math/pca.man math::PCA] [manpage modules/math/polynomials.man math::polynomials] [manpage modules/math/rational_funcs.man math::rationalfunctions] [manpage modules/math/special.man math::special] [manpage modules/math/trig.man math::trig] [manpage modules/simulation/annealing.man simulation::annealing] [manpage modules/simulation/montecarlo.man simulation::montecarlo] [manpage modules/simulation/simulation_random.man simulation::random] [key mathematics] [manpage modules/math/fourier.man math::fourier] [manpage modules/math/statistics.man math::statistics] [key matrices] |
︙ | ︙ | |||
3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 | [manpage modules/treeql/treeql.man treeql] [key {tree walking}] [manpage modules/page/page_util_flow.man page_util_flow] [manpage modules/page/page_util_norm_lemon.man page_util_norm_lemon] [manpage modules/page/page_util_norm_peg.man page_util_norm_peg] [key TreeQL] [manpage modules/treeql/treeql.man treeql] [key trimming] [manpage modules/textutil/textutil.man textutil] [manpage modules/textutil/trim.man textutil::trim] [key twitter] [manpage modules/oauth/oauth.man oauth] [key type] [manpage modules/fileutil/fileutil.man fileutil] | > > | 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 | [manpage modules/treeql/treeql.man treeql] [key {tree walking}] [manpage modules/page/page_util_flow.man page_util_flow] [manpage modules/page/page_util_norm_lemon.man page_util_norm_lemon] [manpage modules/page/page_util_norm_peg.man page_util_norm_peg] [key TreeQL] [manpage modules/treeql/treeql.man treeql] [key trigonometry] [manpage modules/math/trig.man math::trig] [key trimming] [manpage modules/textutil/textutil.man textutil] [manpage modules/textutil/trim.man textutil::trim] [key twitter] [manpage modules/oauth/oauth.man oauth] [key type] [manpage modules/fileutil/fileutil.man fileutil] |
︙ | ︙ |
Changes to support/devel/sak/doc/manpages.txt.
︙ | ︙ | |||
199 200 201 202 203 204 205 206 207 208 209 210 211 212 | modules/math/qcomplex.man modules/math/rational_funcs.man modules/math/roman.man modules/math/romberg.man modules/math/special.man modules/math/statistics.man modules/math/symdiff.man modules/md4/md4.man modules/md5/md5.man modules/md5crypt/md5crypt.man modules/mime/mime.man modules/mime/smtp.man modules/multiplexer/multiplexer.man modules/namespacex/namespacex.man | > | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | modules/math/qcomplex.man modules/math/rational_funcs.man modules/math/roman.man modules/math/romberg.man modules/math/special.man modules/math/statistics.man modules/math/symdiff.man modules/math/trig.man modules/md4/md4.man modules/md5/md5.man modules/md5crypt/md5crypt.man modules/mime/mime.man modules/mime/smtp.man modules/multiplexer/multiplexer.man modules/namespacex/namespacex.man |
︙ | ︙ |
Changes to support/devel/sak/doc/toc.txt.
︙ | ︙ | |||
211 212 213 214 215 216 217 218 219 220 221 222 223 224 | [item modules/math/optimize.man math::optimize {Optimisation routines}] [item modules/math/pca.man math::PCA {Package for Principal Component Analysis}] [item modules/math/polynomials.man math::polynomials {Polynomial functions}] [item modules/math/rational_funcs.man math::rationalfunctions {Polynomial functions}] [item modules/math/roman.man math::roman {Tools for creating and manipulating roman numerals}] [item modules/math/special.man math::special {Special mathematical functions}] [item modules/math/statistics.man math::statistics {Basic statistical functions and procedures}] [item modules/simulation/annealing.man simulation::annealing {Simulated annealing}] [item modules/simulation/montecarlo.man simulation::montecarlo {Monte Carlo simulations}] [item modules/simulation/simulation_random.man simulation::random {Pseudo-random number generators}] [division_end] [division_start Networking] [item modules/asn/asn.man asn {ASN.1 BER encoder/decoder}] [item modules/http/autoproxy.man autoproxy {Automatic HTTP proxy usage and authentication}] | > | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | [item modules/math/optimize.man math::optimize {Optimisation routines}] [item modules/math/pca.man math::PCA {Package for Principal Component Analysis}] [item modules/math/polynomials.man math::polynomials {Polynomial functions}] [item modules/math/rational_funcs.man math::rationalfunctions {Polynomial functions}] [item modules/math/roman.man math::roman {Tools for creating and manipulating roman numerals}] [item modules/math/special.man math::special {Special mathematical functions}] [item modules/math/statistics.man math::statistics {Basic statistical functions and procedures}] [item modules/math/trig.man math::trig {Trigonometric anf hyperbolic functions}] [item modules/simulation/annealing.man simulation::annealing {Simulated annealing}] [item modules/simulation/montecarlo.man simulation::montecarlo {Monte Carlo simulations}] [item modules/simulation/simulation_random.man simulation::random {Pseudo-random number generators}] [division_end] [division_start Networking] [item modules/asn/asn.man asn {ASN.1 BER encoder/decoder}] [item modules/http/autoproxy.man autoproxy {Automatic HTTP proxy usage and authentication}] |
︙ | ︙ | |||
807 808 809 810 811 812 813 814 815 816 817 818 819 820 | [item modules/math/optimize.man math::optimize {Optimisation routines}] [item modules/math/pca.man math::PCA {Package for Principal Component Analysis}] [item modules/math/polynomials.man math::polynomials {Polynomial functions}] [item modules/math/rational_funcs.man math::rationalfunctions {Polynomial functions}] [item modules/math/roman.man math::roman {Tools for creating and manipulating roman numerals}] [item modules/math/special.man math::special {Special mathematical functions}] [item modules/math/statistics.man math::statistics {Basic statistical functions and procedures}] [item modules/math/machineparameters.man tclrep/machineparameters {Compute double precision machine parameters.}] [division_end] [division_start md4] [item modules/md4/md4.man md4 {MD4 Message-Digest Algorithm}] [division_end] [division_start md5] [item modules/md5/md5.man md5 {MD5 Message-Digest Algorithm}] | > | 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | [item modules/math/optimize.man math::optimize {Optimisation routines}] [item modules/math/pca.man math::PCA {Package for Principal Component Analysis}] [item modules/math/polynomials.man math::polynomials {Polynomial functions}] [item modules/math/rational_funcs.man math::rationalfunctions {Polynomial functions}] [item modules/math/roman.man math::roman {Tools for creating and manipulating roman numerals}] [item modules/math/special.man math::special {Special mathematical functions}] [item modules/math/statistics.man math::statistics {Basic statistical functions and procedures}] [item modules/math/trig.man math::trig {Trigonometric anf hyperbolic functions}] [item modules/math/machineparameters.man tclrep/machineparameters {Compute double precision machine parameters.}] [division_end] [division_start md4] [item modules/md4/md4.man md4 {MD4 Message-Digest Algorithm}] [division_end] [division_start md5] [item modules/md5/md5.man md5 {MD5 Message-Digest Algorithm}] |
︙ | ︙ |
Changes to support/devel/sak/doc/toc_cats.txt.
︙ | ︙ | |||
211 212 213 214 215 216 217 218 219 220 221 222 223 224 | [item modules/math/optimize.man math::optimize {Optimisation routines}] [item modules/math/pca.man math::PCA {Package for Principal Component Analysis}] [item modules/math/polynomials.man math::polynomials {Polynomial functions}] [item modules/math/rational_funcs.man math::rationalfunctions {Polynomial functions}] [item modules/math/roman.man math::roman {Tools for creating and manipulating roman numerals}] [item modules/math/special.man math::special {Special mathematical functions}] [item modules/math/statistics.man math::statistics {Basic statistical functions and procedures}] [item modules/simulation/annealing.man simulation::annealing {Simulated annealing}] [item modules/simulation/montecarlo.man simulation::montecarlo {Monte Carlo simulations}] [item modules/simulation/simulation_random.man simulation::random {Pseudo-random number generators}] [division_end] [division_start Networking] [item modules/asn/asn.man asn {ASN.1 BER encoder/decoder}] [item modules/http/autoproxy.man autoproxy {Automatic HTTP proxy usage and authentication}] | > | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | [item modules/math/optimize.man math::optimize {Optimisation routines}] [item modules/math/pca.man math::PCA {Package for Principal Component Analysis}] [item modules/math/polynomials.man math::polynomials {Polynomial functions}] [item modules/math/rational_funcs.man math::rationalfunctions {Polynomial functions}] [item modules/math/roman.man math::roman {Tools for creating and manipulating roman numerals}] [item modules/math/special.man math::special {Special mathematical functions}] [item modules/math/statistics.man math::statistics {Basic statistical functions and procedures}] [item modules/math/trig.man math::trig {Trigonometric anf hyperbolic functions}] [item modules/simulation/annealing.man simulation::annealing {Simulated annealing}] [item modules/simulation/montecarlo.man simulation::montecarlo {Monte Carlo simulations}] [item modules/simulation/simulation_random.man simulation::random {Pseudo-random number generators}] [division_end] [division_start Networking] [item modules/asn/asn.man asn {ASN.1 BER encoder/decoder}] [item modules/http/autoproxy.man autoproxy {Automatic HTTP proxy usage and authentication}] |
︙ | ︙ |
Changes to support/devel/sak/doc/toc_mods.txt.
︙ | ︙ | |||
312 313 314 315 316 317 318 319 320 321 322 323 324 325 | [item modules/math/optimize.man math::optimize {Optimisation routines}] [item modules/math/pca.man math::PCA {Package for Principal Component Analysis}] [item modules/math/polynomials.man math::polynomials {Polynomial functions}] [item modules/math/rational_funcs.man math::rationalfunctions {Polynomial functions}] [item modules/math/roman.man math::roman {Tools for creating and manipulating roman numerals}] [item modules/math/special.man math::special {Special mathematical functions}] [item modules/math/statistics.man math::statistics {Basic statistical functions and procedures}] [item modules/math/machineparameters.man tclrep/machineparameters {Compute double precision machine parameters.}] [division_end] [division_start md4] [item modules/md4/md4.man md4 {MD4 Message-Digest Algorithm}] [division_end] [division_start md5] [item modules/md5/md5.man md5 {MD5 Message-Digest Algorithm}] | > | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | [item modules/math/optimize.man math::optimize {Optimisation routines}] [item modules/math/pca.man math::PCA {Package for Principal Component Analysis}] [item modules/math/polynomials.man math::polynomials {Polynomial functions}] [item modules/math/rational_funcs.man math::rationalfunctions {Polynomial functions}] [item modules/math/roman.man math::roman {Tools for creating and manipulating roman numerals}] [item modules/math/special.man math::special {Special mathematical functions}] [item modules/math/statistics.man math::statistics {Basic statistical functions and procedures}] [item modules/math/trig.man math::trig {Trigonometric anf hyperbolic functions}] [item modules/math/machineparameters.man tclrep/machineparameters {Compute double precision machine parameters.}] [division_end] [division_start md4] [item modules/md4/md4.man md4 {MD4 Message-Digest Algorithm}] [division_end] [division_start md5] [item modules/md5/md5.man md5 {MD5 Message-Digest Algorithm}] |
︙ | ︙ |
Changes to support/installation/modules.tcl.
︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 | Module base64 _tcl _man _null Module bee _tcl _man _null Module bench _tcl _null _null Module bibtex _tcl _man _exa Module blowfish _tcl _man _null Module cache _tcl _man _null Module calendar _tci _man _null Module clock _tcl _man _null Module cmdline _tcl _man _null Module comm _tcl _man _null Module control _tci _man _null Module coroutine _tcl _null _null Module counter _tcl _man _null Module crc _tcl _man _null | > | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | Module base64 _tcl _man _null Module bee _tcl _man _null Module bench _tcl _null _null Module bibtex _tcl _man _exa Module blowfish _tcl _man _null Module cache _tcl _man _null Module calendar _tci _man _null Module clay _tcl _man _null Module clock _tcl _man _null Module cmdline _tcl _man _null Module comm _tcl _man _null Module control _tci _man _null Module coroutine _tcl _null _null Module counter _tcl _man _null Module crc _tcl _man _null |
︙ | ︙ |