summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/doctools2toc
diff options
context:
space:
mode:
Diffstat (limited to 'tcllib/modules/doctools2toc')
-rw-r--r--tcllib/modules/doctools2toc/ChangeLog103
-rw-r--r--tcllib/modules/doctools2toc/container.tcl545
-rw-r--r--tcllib/modules/doctools2toc/container.test53
-rw-r--r--tcllib/modules/doctools2toc/export.tcl125
-rw-r--r--tcllib/modules/doctools2toc/export.test212
-rw-r--r--tcllib/modules/doctools2toc/export_doctoc.man7
-rw-r--r--tcllib/modules/doctools2toc/export_doctoc.tcl217
-rw-r--r--tcllib/modules/doctools2toc/export_doctoc.test77
-rw-r--r--tcllib/modules/doctools2toc/export_html.tcl323
-rw-r--r--tcllib/modules/doctools2toc/export_html.test76
-rw-r--r--tcllib/modules/doctools2toc/export_json.tcl223
-rw-r--r--tcllib/modules/doctools2toc/export_json.test74
-rw-r--r--tcllib/modules/doctools2toc/export_nroff.tcl218
-rw-r--r--tcllib/modules/doctools2toc/export_nroff.test73
-rw-r--r--tcllib/modules/doctools2toc/export_text.tcl142
-rw-r--r--tcllib/modules/doctools2toc/export_text.test63
-rw-r--r--tcllib/modules/doctools2toc/export_wiki.tcl144
-rw-r--r--tcllib/modules/doctools2toc/export_wiki.test63
-rw-r--r--tcllib/modules/doctools2toc/import.tcl191
-rw-r--r--tcllib/modules/doctools2toc/import.test377
-rw-r--r--tcllib/modules/doctools2toc/import_doctoc.man6
-rw-r--r--tcllib/modules/doctools2toc/import_doctoc.tcl91
-rw-r--r--tcllib/modules/doctools2toc/import_doctoc.test92
-rw-r--r--tcllib/modules/doctools2toc/import_json.tcl77
-rw-r--r--tcllib/modules/doctools2toc/import_json.test115
-rw-r--r--tcllib/modules/doctools2toc/include/concept.inc47
-rw-r--r--tcllib/modules/doctools2toc/include/dependencies.inc44
-rw-r--r--tcllib/modules/doctools2toc/include/export/config/doctoc.inc70
-rw-r--r--tcllib/modules/doctools2toc/include/export/config/html.inc155
-rw-r--r--tcllib/modules/doctools2toc/include/export/config/json.inc39
-rw-r--r--tcllib/modules/doctools2toc/include/export/config/nroff.inc40
-rw-r--r--tcllib/modules/doctools2toc/include/export/config/text.inc21
-rw-r--r--tcllib/modules/doctools2toc/include/export/config/wiki.inc32
-rw-r--r--tcllib/modules/doctools2toc/include/export/format/html.inc3
-rw-r--r--tcllib/modules/doctools2toc/include/export/format/json.inc1
-rw-r--r--tcllib/modules/doctools2toc/include/export/format/nroff.inc2
-rw-r--r--tcllib/modules/doctools2toc/include/export/format/null.inc0
-rw-r--r--tcllib/modules/doctools2toc/include/export/format/text.inc1
-rw-r--r--tcllib/modules/doctools2toc/include/export/plugin.inc55
-rw-r--r--tcllib/modules/doctools2toc/include/format/doctoc.inc22
-rw-r--r--tcllib/modules/doctools2toc/include/format/json.inc74
-rw-r--r--tcllib/modules/doctools2toc/include/import/config/doctoc.inc1
-rw-r--r--tcllib/modules/doctools2toc/include/import/config/json.inc1
-rw-r--r--tcllib/modules/doctools2toc/include/import/format/doctoc.inc12
-rw-r--r--tcllib/modules/doctools2toc/include/import/format/json.inc2
-rw-r--r--tcllib/modules/doctools2toc/include/import/plugin.inc55
-rw-r--r--tcllib/modules/doctools2toc/include/msgcat.inc46
-rw-r--r--tcllib/modules/doctools2toc/include/serialization.inc131
-rw-r--r--tcllib/modules/doctools2toc/msgcat_c.tcl28
-rw-r--r--tcllib/modules/doctools2toc/msgcat_de.tcl28
-rw-r--r--tcllib/modules/doctools2toc/msgcat_en.tcl28
-rw-r--r--tcllib/modules/doctools2toc/msgcat_fr.tcl31
-rw-r--r--tcllib/modules/doctools2toc/parse.tcl1058
-rw-r--r--tcllib/modules/doctools2toc/parse.test153
-rw-r--r--tcllib/modules/doctools2toc/pkgIndex.tcl33
-rw-r--r--tcllib/modules/doctools2toc/structure.tcl388
-rw-r--r--tcllib/modules/doctools2toc/structure.test212
-rw-r--r--tcllib/modules/doctools2toc/tests/container379
-rw-r--r--tcllib/modules/doctools2toc/tests/container_main1003
-rw-r--r--tcllib/modules/doctools2toc/tests/data/bad_command1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/empty0
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/badtrees.tcl23
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/01_nonwhitespace11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/02_nonwhitespace21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/03_illegalcmd11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/04_illegalcmd21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/05_nestingbad11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/06_nestingbad21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/07_wrongargs1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/08_toomanyargs1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/09_vsetvarunknown1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/10_vsetvarerr1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/11_vsetvalueerr1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/12_incerror1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/13_incnotfound1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/14_incempty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/15_incbadeof1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/16_incbadchar1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/17_badempty0
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/18_nobegin1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/19_manybegin5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/20_latebegin3
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/21_noend11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/22_noend22
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/23_manyend5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/24_earlyend4
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/25_nobeginend2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/26_nodivbegin3
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/27_incbadcmd1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/28_badredef4
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/29_badredef25
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/30_manydivbegin5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/31_nodivend3
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/doctoc/32_manydivend5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/01_nonwhitespace11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/02_nonwhitespace21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/03_illegalcmd11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/04_illegalcmd21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/05_nestingbad11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/06_nestingbad21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/07_wrongargs1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/08_toomanyargs1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/09_vsetvarunknown1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/10_vsetvarerr1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/11_vsetvalueerr1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/12_incerror1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/13_incnotfound1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/14_incempty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/15_incbadeof1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/16_incbadchar1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/17_badempty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/18_nobegin1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/19_manybegin1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/20_latebegin1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/21_noend11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/22_noend21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/23_manyend1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/24_earlyend1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/25_nobeginend1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/26_nodivbegin1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/27_incbadcmd1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/28_badredef1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/29_badredef21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/30_manydivbegin1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/31_nodivend1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/ecode/32_manydivend1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/01_nonwhitespace11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/02_nonwhitespace21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/03_illegalcmd11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/04_illegalcmd21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/05_nestingbad11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/06_nestingbad21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/07_wrongargs1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/08_toomanyargs1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/09_vsetvarunknown1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/10_vsetvarerr1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/11_vsetvalueerr1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/12_incerror1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/13_incnotfound1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/14_incempty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/15_incbadeof2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/16_incbadchar2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/17_badempty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/18_nobegin1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/19_manybegin3
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/20_latebegin2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/21_noend11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/22_noend21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/23_manyend3
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/24_earlyend1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/25_nobeginend2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/26_nodivbegin1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/27_incbadcmd1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/28_badredef1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/29_badredef21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/30_manydivbegin2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/31_nodivend2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/emsg/32_manydivend3
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/00_short1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/01_tag1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/02_cshort1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/03_misslabel1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/04_misstitle1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/05_missitems1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/07_cshort21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/08_etag1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/09_cshort32
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/10_missid1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/11_misslabel22
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/12_missdesc2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/14_dshort2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/15_misslabel33
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/16_missitems21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/19_duplabel1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/20_duplabel21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json-emsg/21_duplabel31
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/00_short2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/01_tag4
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/02_cshort4
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/03_misslabel7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/04_misstitle7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/05_missitems7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/07_cshort27
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/08_etag7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/09_cshort37
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/10_missid11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/11_misslabel211
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/12_missdesc11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/14_dshort7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/15_misslabel310
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/16_missitems210
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/19_duplabel15
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/20_duplabel215
-rw-r--r--tcllib/modules/doctools2toc/tests/data/fail/json/21_duplabel315
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/1_empty2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/2_references5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/3_toc7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/4_toc27
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/1_empty2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/2_references5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/3_toc7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/4_toc27
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/1_empty2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/2_references5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/3_toc7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/4_toc27
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/1_empty2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/2_references5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/3_toc7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/4_toc27
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/1_empty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/2_references1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/3_toc1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/4_toc21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc/1_empty2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc/2_references5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc/3_toc7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/doctoc/4_toc27
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-compact/1_empty20
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-compact/2_references30
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-compact/3_toc37
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-compact/4_toc237
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-indented/1_empty20
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-indented/2_references30
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-indented/3_toc37
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-indented/4_toc237
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/1_empty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/2_references1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/3_toc1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/4_toc21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-indalign/1_empty7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-indalign/2_references25
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-indalign/3_toc31
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-indalign/4_toc231
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-indented/1_empty7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-indented/2_references25
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-indented/3_toc31
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-indented/4_toc231
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/1_empty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/2_references1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/3_toc1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/4_toc21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json/1_empty7
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json/2_references25
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json/3_toc31
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/json/4_toc231
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/nroff-external/1_empty4
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/nroff-external/2_references14
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/nroff-external/3_toc19
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/nroff-external/4_toc219
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/1_empty3
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/2_references13
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/3_toc18
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/4_toc218
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/serial-print/1_empty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/serial-print/2_references4
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/serial-print/3_toc5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/serial-print/4_toc25
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/serial/1_empty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/serial/2_references1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/serial/3_toc2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/serial/4_toc21
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/text/1_empty2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/text/2_references11
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/text/3_toc14
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/text/4_toc215
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/wiki/1_empty1
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/wiki/2_references5
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/wiki/3_toc6
-rw-r--r--tcllib/modules/doctools2toc/tests/data/ok/wiki/4_toc26
-rw-r--r--tcllib/modules/doctools2toc/tests/data/unexpected_char2
-rw-r--r--tcllib/modules/doctools2toc/tests/data/unexpected_eof1
-rw-r--r--tcllib/modules/doctools2toc/tests/export147
-rw-r--r--tcllib/modules/doctools2toc/tests/export_doctoc5
-rw-r--r--tcllib/modules/doctools2toc/tests/export_text5
-rw-r--r--tcllib/modules/doctools2toc/tests/import174
-rw-r--r--tcllib/modules/doctools2toc/tests/import_doctoc73
-rw-r--r--tcllib/modules/doctools2toc/tests/parse130
-rw-r--r--tcllib/modules/doctools2toc/toc_container.man370
-rw-r--r--tcllib/modules/doctools2toc/toc_export.man306
-rw-r--r--tcllib/modules/doctools2toc/toc_export_html.man7
-rw-r--r--tcllib/modules/doctools2toc/toc_export_json.man7
-rw-r--r--tcllib/modules/doctools2toc/toc_export_nroff.man7
-rw-r--r--tcllib/modules/doctools2toc/toc_export_text.man7
-rw-r--r--tcllib/modules/doctools2toc/toc_export_wiki.man7
-rw-r--r--tcllib/modules/doctools2toc/toc_import.man394
-rw-r--r--tcllib/modules/doctools2toc/toc_import_json.man6
-rw-r--r--tcllib/modules/doctools2toc/toc_introduction.man143
-rw-r--r--tcllib/modules/doctools2toc/toc_msgcat_c.man5
-rw-r--r--tcllib/modules/doctools2toc/toc_msgcat_de.man5
-rw-r--r--tcllib/modules/doctools2toc/toc_msgcat_en.man5
-rw-r--r--tcllib/modules/doctools2toc/toc_msgcat_fr.man5
-rw-r--r--tcllib/modules/doctools2toc/toc_parse.man175
-rw-r--r--tcllib/modules/doctools2toc/toc_structure.man151
294 files changed, 11200 insertions, 0 deletions
diff --git a/tcllib/modules/doctools2toc/ChangeLog b/tcllib/modules/doctools2toc/ChangeLog
new file mode 100644
index 0000000..6090d9d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/ChangeLog
@@ -0,0 +1,103 @@
+2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.15 ========================
+ *
+
+2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.14 ========================
+ *
+
+2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.13 ========================
+ *
+
+2010-11-23 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * export_doctoc.man: Added headers to properly mark files as manpages
+ * export_html.man: even if not containing having manpage_begin, and
+ * export_json.man: vice versa, preventing recognition of subordinate
+ * export_nroff.man: include files as manpages.
+ * export_text.man:
+ * export_wiki.man:
+ * import_doctoc.man:
+ * import_json.man:
+ * include/export/plugin.inc:
+ * include/import/plugin.inc:
+ * include/msgcat.inc:
+ * msgcat_c.man:
+ * msgcat_de.man:
+ * msgcat_en.man:
+ * msgcat_fr.man:
+
+2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.12 ========================
+ *
+
+2009-11-14 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * container.test: Fixed up typos in comments refering to keyword
+ * export.tcl: indices, while the packages are all about tables of
+ * export_doctoc.tcl: contents. Unchanged functionality, version
+ * export_doctoc.test: left unchanged.
+ * export_html.tcl:
+ * export_html.test:
+ * export_json.tcl:
+ * export_json.test:
+ * export_nroff.tcl:
+ * export_nroff.test:
+ * export_text.tcl:
+ * export_text.test:
+ * export_wiki.tcl:
+ * export_wiki.test:
+ * import.tcl:
+ * import_doctoc.tcl:
+ * import_json.tcl:
+ * include/export/config/doctoc.inc:
+ * include/export/config/html.inc:
+ * include/export/config/nroff.inc:
+ * include/export/plugin.inc:
+ * include/import/plugin.inc:
+ * parse.tcl:
+ * tests/container:
+ * tests/export:
+ * tests/import:
+
+2009-08-07 Andreas Kupries <andreask@activestate.com>
+
+ * export_doctoc.tcl: Added missing '@mdgen NODEP' hints for the
+ * export_html.tcl: pseudo-packages 'doctools::toc::export::plugin'
+ * export_json.tcl: and 'doctools::toc::import::plugin' to keep them
+ * export_nroff.tcl: out of the requirements listed in the meta data.
+ * export_text.tcl:
+ * export_wiki.tcl:
+ * import_doctoc.tcl:
+ * import_json.tcl:
+
+2009-04-27 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * container.test: Updated the nroff export plugin and related files
+ * export.test: to new name of the nroff man.macros package. Bumped
+ * export_nroff.tcl: to version 0.2.
+ * export_nroff.test:
+ * pkgIndex.tcl:
+ * include/dependencies.inc:
+ * include/export/format/nroff.inc:
+
+ * include/export/plugin.inc: Made version info configurable
+ * export_docidx.tcl: Version 0.1, unchanged
+ * export_json.tcl: Version 0.1, unchanged
+ * export_html.tcl: Version 0.1, unchanged
+ * export_text.tcl: Version 0.1, unchanged
+ * export_wiki.tcl: Version 0.1, unchanged
+ * export_nroff.tcl: Bumped version to 0.2.
+
+2009-04-18 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * Doctools version 2, processing tables of contents.
diff --git a/tcllib/modules/doctools2toc/container.tcl b/tcllib/modules/doctools2toc/container.tcl
new file mode 100644
index 0000000..bfc66c7
--- /dev/null
+++ b/tcllib/modules/doctools2toc/container.tcl
@@ -0,0 +1,545 @@
+# doctoc.tcl --
+#
+# Implementation of doctoc objects for Tcl. v2.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: container.tcl,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# Each object manages one table of contents, with methods to add and
+# remove entries and divisions, singly, or in bulk. The bulk methods
+# accept various forms of textual serializations, among them text
+# using the doctoc markup language.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require Tcl 8.4
+package require doctools::toc::structure
+package require snit
+package require struct::tree
+
+# ### ### ### ######### ######### #########
+## API
+
+snit::type ::doctools::toc {
+
+ # Concepts:
+ # - A table of contents consists of an ordered set of elements,
+ # references and divisions.
+ # - Both type of elements within the table are identified by their
+ # label.
+ # - A reference has two additional pieces of information,
+ # the id of the document it references, and a textual description.
+ # - A division may have the id of a document.
+ # - The main data of a division is an ordered set of elements,
+ # references and divisions.
+ # - Both type of elements within the division are identified by
+ # their label.
+ # - The definitions above define a tree of elements, with
+ # references as leafs, and divisions as the inner nodes.
+ # - Regarding identification, the full label of each element is
+ # the list of per-node labels on the path from the root of the
+ # tree to the element itself.
+
+ # ### ### ### ######### ######### #########
+ ## Options
+
+ ## None
+
+ # ### ### ### ######### ######### #########
+ ## Methods
+
+ constructor {} {
+ install mytree using struct::tree ${selfns}::T
+ # Root is a fake division
+ set myroot [$mytree rootname]
+ $mytree set $myroot type division
+ $mytree set $myroot label {}
+ $mytree set $myroot labelindex {}
+ return
+ }
+
+ # Default destructor.
+
+ # ### ### ### ######### ######### #########
+
+ method invalidate {} {
+ array unset mytoc *
+ return
+ }
+
+ # ### ### ### ######### ######### #########
+
+ method title {{text {}}} {
+ if {[llength [info level 0]] == 6} {
+ set mytitle $text
+ }
+ return $mytitle
+ }
+
+ method label {{text {}}} {
+ if {[llength [info level 0]] == 6} {
+ set mylabel $text
+ $mytree set $myroot label $text
+ }
+ return $mylabel
+ }
+
+ method exporter {{object {}}} {
+ # TODO :: unlink/link change notification callbacks on the
+ # config/include components so that we can invalidate our
+ # cache when the settings change.
+
+ if {[llength [info level 0]] == 6} {
+ set myexporter $object
+ }
+ return $myexporter
+ }
+
+ method importer {{object {}}} {
+ if {[llength [info level 0]] == 6} {
+ set myimporter $object
+ }
+ return $myimporter
+ }
+
+ # ### ### ### ######### ######### #########
+ ## Direct manipulation of the table of contents.
+
+ method {+ reference} {pid label docid desc} {
+ CheckDiv $pid
+ if {$docid eq {}} {
+ return -code error "Illegal empty document reference for reference entry"
+ }
+
+ array set l [$mytree get $pid labelindex]
+ if {[info exists l($label)]} {
+ return -code error "Redefinition of label '$label' in '[$self full-label $pid]'"
+ }
+
+ set new [$mytree insert $pid end]
+ set l($label) $new
+ $mytree set $pid labelindex [array get l]
+
+ $mytree set $new type reference
+ $mytree set $new label $label
+ $mytree set $new document $docid
+ $mytree set $new description $desc
+
+ array unset mytoc *
+ return $new
+ }
+
+ method {+ division} {pid label {docid {}}} {
+ CheckDiv $pid
+
+ array set l [$mytree get $pid labelindex]
+ if {[info exists l($label)]} {
+ return -code error "Redefinition of label '$label' in '[$self full-label $pid]'"
+ }
+
+ set new [$mytree insert $pid end]
+ set l($label) $new
+ $mytree set $pid labelindex [array get l]
+
+ $mytree set $new type division
+ $mytree set $new label $label
+ if {$docid ne {}} {
+ $mytree set $new document $docid
+ }
+ $mytree set $new labelindex {}
+
+ array unset mytoc *
+ return $new
+ }
+
+ method remove {id} {
+ Check $id
+ if {$id eq $myroot} {
+ return -code error {Unable to remove root}
+ }
+ set pid [$mytree parent $id]
+ set label [$mytree get $id label]
+
+ array set l [$mytree get $pid labelindex]
+ unset l($label)
+ $mytree set $pid labelindex [array get l]
+ $mytree delete $id
+
+ array unset mytoc *
+ return
+ }
+
+ # ### ### ### ######### ######### #########
+
+ method up {id} {
+ Check $id
+ return [$mytree parent $id]
+ }
+
+ method next {id} {
+ Check $id
+ set n [$mytree next $id]
+ if {$n eq {}} { set n [$mytree parent $id] }
+ return $n
+ }
+
+ method prev {id} {
+ Check $id
+ set n [$mytree previous $id]
+ if {$n eq {}} { set n [$mytree parent $id] }
+ return $n
+ }
+
+ method child {id label args} {
+ CheckDiv $id
+ # Find the id of the element with the given labels, in the
+ # parent element id.
+ foreach label [linsert $args 0 $label] {
+ array set l [$mytree get $id labelindex]
+ if {![info exists l($label)]} {
+ return -code error "Bad label '$label' in '[$self full-label $id]'"
+ }
+ set id $l($label)
+ unset l
+ }
+ return $id
+ }
+
+ method element {args} {
+ if {![llength $args]} { return $myroot }
+ # 8.5: $self child $myroot {*}$args
+ return [eval [linsert $args 0 $self child $myroot]]
+ }
+
+ method children {id} {
+ CheckDiv $id
+ return [$mytree children $id]
+ }
+
+ # ### ### ### ######### ######### #########
+
+ method type {id} {
+ Check $id
+ return [$mytree get $id type]
+ }
+
+ method full-label {id} {
+ Check $id
+ set result {}
+ foreach node [struct::list reverse [lrange [$mytree ancestors $id] 0 end-1]] {
+ lappend result [$mytree get $node label]
+ }
+ lappend result [$mytree get $id label]
+
+ return $result
+ }
+
+ method elabel {id {newlabel {}}} {
+ Check $id
+ set thelabel [$mytree get $id label]
+ if {
+ ([llength [info level 0]] == 7) &&
+ ($newlabel ne $thelabel)
+ } {
+ # Handle only calls which change the label
+
+ set parent [$mytree parent $id]
+ array set l [$mytree get $parent labelindex]
+
+ if {[info exists l($newlabel)]} {
+ return -code error "Redefinition of label '$newlabel' in '[$self full-label $parent]'"
+ }
+
+ # Copy node information and re-label.
+ set l($newlabel) $l($thelabel)
+ unset l($thelabel)
+ $mytree set $id label $newlabel
+ $mytree set $parent labelindex [array get l]
+
+ if {$id eq $myroot} {
+ set mylabel $newlabel
+ }
+
+ set thelabel $newlabel
+ }
+ return $thelabel
+ }
+
+ method description {id {newdesc {}}} {
+ Check $id
+ if {[$mytree get $id type] eq "division"} {
+ return -code error "Divisions have no description"
+ }
+ set thedescription [$mytree get $id description]
+ if {
+ ([llength [info level 0]] == 7) &&
+ ($newdesc ne $thedescription)
+ } {
+ # Handle only calls which change the description
+ $mytree set $id description $newdesc
+
+ set thedescription $newdesc
+ }
+ return $thedescription
+ }
+
+ method document {id {newdocid {}}} {
+ Check $id
+ set thedocid {}
+ catch {
+ set thedocid [$mytree get $id document]
+ }
+ if {
+ ([llength [info level 0]] == 7) &&
+ ($newdocid ne $thedocid)
+ } {
+ # Handle only calls which change the document
+ if {$newdocid eq {}} {
+ if {[$mytree get $id type] eq "division"} {
+ $mytree unset $id document
+ } else {
+ return -code error "Illegal to unset document reference in reference entry"
+ }
+ } else {
+ $mytree set $id document $newdocid
+ }
+ set thedocid $newdocid
+ }
+ return $thedocid
+ }
+
+ # ### ### ### ######### ######### #########
+ ## Public methods. Bulk loading and merging.
+
+ method {deserialize =} {data {format {}}} {
+ # Default format is the regular toc serialization
+ if {$format eq {}} {
+ set format serial
+ }
+
+ if {$format ne "serial"} {
+ set data [$self Import $format $data]
+ # doctools::toc::structure verify-as-canonical $data
+ # ImportSerial verifies.
+ }
+
+ $self ImportSerial $data
+ return
+ }
+
+ method {deserialize +=} {data {format {}}} {
+ # Default format is the regular toc serialization
+ if {$format eq {}} {
+ set format serial
+ }
+
+ if {$format ne "serial"} {
+ set data [$self Import $format $data]
+ # doctools::toc::structure verify-as-canonical $data
+ # merge or ImportSerial verify the structure.
+ }
+
+ set data [doctools::toc::structure merge [$self serialize] $data]
+ # doctools::toc::structure verify-as-canonical $data
+ # ImportSerial verifies.
+
+ $self ImportSerial $data
+ return
+ }
+
+ # ### ### ### ######### ######### #########
+
+ method serialize {{format {}}} {
+ # Default format is the regular toc serialization
+ if {$format eq {}} {
+ set format serial
+ }
+
+ # First check the cache for a remebered representation of the
+ # toc for the chosen format, and return it, if such is known.
+
+ if {[info exists mytoc($format)]} {
+ return $mytoc($format)
+ }
+
+ # If there is no cached representation we have to generate it
+ # from it from our internal representation.
+
+ if {$format eq "serial"} {
+ return [$self GenerateSerial]
+ } else {
+ return [$self Generate $format]
+ }
+
+ return -code error "Internal error, reached unreachable location"
+ }
+
+ # ### ### ### ######### ######### #########
+ ## Internal methods
+
+ proc Check {id} {
+ upvar 1 mytree mytree
+ if {![$mytree exists $id]} {
+ return -code error "Bad toc element handle '$id'"
+ }
+ return
+ }
+
+ proc CheckDiv {id} {
+ upvar 1 mytree mytree
+ Check $id
+ if {[$mytree get $id type] ne "division"} {
+ return -code error "toc element handle '$id' does not refer to a division"
+ }
+ }
+
+ method GenerateSerial {} {
+ # We can generate the list serialization easily from the
+ # internal representation.
+
+ # Construct result
+ set serial [list doctools::toc \
+ [list \
+ items [$self GenerateDivision $myroot] \
+ label $mylabel \
+ title $mytitle]]
+
+ # This is just present to assert that the code above creates
+ # correct serializations.
+ doctools::toc::structure verify-as-canonical $serial
+
+ set mytoc(serial) $serial
+ return $serial
+ }
+
+ method GenerateDivision {root} {
+ upvar 1 mytree mytree
+ set div {}
+ foreach id [$mytree children $root] {
+ set etype [$mytree get $id type]
+ set edata {}
+ switch -exact -- $etype {
+ reference {
+ lappend edata \
+ desc [$mytree get $id description] \
+ id [$mytree get $id document] \
+ label [$mytree get $id label]
+ }
+ division {
+ if {[$mytree keyexists $id document]} {
+ lappend edata id [$mytree get $id document]
+ }
+ lappend edata \
+ items [$self GenerateDivision $id] \
+ label [$mytree get $id label]
+ }
+ }
+ lappend div [list $etype $edata]
+ }
+ return $div
+ }
+
+ method Generate {format} {
+ if {$myexporter eq {}} {
+ return -code error "Unable to export from \"$format\", no exporter configured"
+ }
+ set res [$myexporter export object $self $format]
+ set mytoc($format) $res
+ return $res
+ }
+
+ method ImportSerial {serial} {
+ doctools::toc::structure verify $serial iscanonical
+
+ # Kill existing content
+ foreach id [$mytree children $myroot] {
+ $mytree delete $id
+ }
+
+ # Unpack the serialization.
+ array set toc $serial
+ array set toc $toc(doctools::toc)
+ unset toc(doctools::toc)
+
+ # We are setting the relevant variables directly instead of
+ # going through the accessor methods.
+
+ set mytitle $toc(title)
+ set mylabel $toc(label)
+
+ $self ImportDivision $toc(items) $myroot
+
+ # Extend cache (only if canonical, as we return only canonical
+ # data).
+ if {$iscanonical} {
+ set mytoc(serial) $serial
+ }
+ return
+ }
+
+ method ImportDivision {items root} {
+ foreach element $items {
+ foreach {etype edata} $element break
+ #struct::list assign $element etype edata
+ array set toc $edata
+ switch -exact -- $etype {
+ reference {
+ $self + reference $root \
+ $toc(label) $toc(id) $toc(desc)
+ }
+ division {
+ if {[info exists toc(id)]} {
+ set div [$self + division $root $toc(label) $toc(id)]
+ } else {
+ set div [$self + division $root $toc(label)]
+ }
+ $self ImportDivision $toc(items) $div
+ }
+ }
+ unset toc
+ }
+ return
+ }
+
+ method Import {format data} {
+ if {$myimporter eq {}} {
+ return -code error "Unable to import from \"$format\", no importer configured"
+ }
+
+ return [$myimporter import text $data $format]
+ }
+
+ # ### ### ### ######### ######### #########
+ ## State
+
+ # References to export/import managers extending the
+ # (de)serialization abilities of the table of contents.
+ variable myexporter {}
+ variable myimporter {}
+
+ # Internal representation of the table of contents.
+
+ variable mytitle {} ; #
+ variable mylabel {} ; #
+ variable mytree {} ; # Tree object holding the toc.
+ variable myroot {} ; # Name of the tree root node.
+
+ # Array serving as cache holding alternative representations of
+ # the toc generated via 'serialize', i.e. data export.
+
+ variable mytoc -array {}
+
+ ##
+ # ### ### ### ######### ######### #########
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc 2
+return
diff --git a/tcllib/modules/doctools2toc/container.test b/tcllib/modules/doctools2toc/container.test
new file mode 100644
index 0000000..1037fb9
--- /dev/null
+++ b/tcllib/modules/doctools2toc/container.test
@@ -0,0 +1,53 @@
+# -*- tcl -*-
+# toc.test: Tests for the doctools::toc package. ToC management.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: container.test,v 1.3 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2
+
+support {
+ useAccel [useTcllibC] struct/tree.tcl struct::tree
+ TestAccelInit struct::tree
+
+ use struct/list.tcl struct::list
+ use snit/snit.tcl snit
+ use fileutil/fileutil.tcl fileutil
+ use log/logger.tcl logger
+ use pluginmgr/pluginmgr.tcl pluginmgr
+
+ use doctools2base/config.tcl doctools::config
+ use doctools2base/paths.tcl doctools::paths
+ useLocal export.tcl doctools::toc::export
+ useLocal import.tcl doctools::toc::import
+ use doctools2base/nroff_manmacros.tcl doctools::nroff::man_macros
+
+ source [tcllibPath doctools2base/tests/common]
+}
+testing {
+ useLocalKeep container.tcl doctools::toc
+}
+
+# -------------------------------------------------------------------------
+
+setup_plugins
+
+# -------------------------------------------------------------------------
+
+TestAccelDo struct::tree impl {
+ source [localPath tests/container_main]
+}
+
+#----------------------------------------------------------------------
+TestAccelExit struct::tree
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/export.tcl b/tcllib/modules/doctools2toc/export.tcl
new file mode 100644
index 0000000..91b7e09
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export.tcl
@@ -0,0 +1,125 @@
+# doctoc.tcl --
+#
+# Exporting indices into other formats.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: export.tcl,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# Each object manages a set of plugins for the conversion of keyword
+# indices into some textual representation. I.e. this object manages
+# the conversion to specialized serializations of keyword indices.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require Tcl 8.4
+package require doctools::config
+package require doctools::toc::structure
+package require pluginmgr
+package require snit
+
+# ### ### ### ######### ######### #########
+## API
+
+snit::type ::doctools::toc::export {
+
+ # ### ### ### ######### ######### #########
+ ## Options :: None
+
+ # ### ### ### ######### ######### #########
+ ## Creation, destruction.
+
+ constructor {} {
+ install myconfig using ::doctools::config ${selfns}::config
+ return
+ }
+
+ destructor {
+ $myconfig destroy
+ # Clear the cache of loaded export plugins.
+ foreach k [array names myplugin] {
+ $myplugin($k) destroy
+ }
+ return
+ }
+
+ # ### ### ### ######### ######### #########
+ ## Convert from the Tcl toc serialization to other formats.
+
+ method {export object} {obj {format {}}} {
+ return [$self export serial [$obj serialize] $format]
+ }
+
+ method {export serial} {serial {format {}}} {
+ doctools::toc::structure verify $serial iscanonical
+
+ set plugin [$self GetPlugin $format]
+
+ # We have a plugin, now feed it.
+
+ if {!$iscanonical} {
+ set serial [doctools::toc::structure canonicalize $serial]
+ }
+
+ set configuration [$myconfig get]
+ lappend configuration user $::tcl_platform(user)
+ lappend configuraton format [$plugin plugin]
+
+ return [$plugin do export $serial $configuration]
+ }
+
+ # ### ### ### ######### ######### #########
+ ## Internal methods
+
+ method GetPlugin {format} {
+ if {$format eq {}} { set format doctoc }
+
+ if {![info exists myplugin($format)]} {
+ set plugin [pluginmgr ${selfns}::fmt-$format \
+ -pattern doctools::toc::export::* \
+ -api { export } \
+ -setup [mymethod PluginSetup]]
+ ::pluginmgr::paths $plugin doctools::toc::export
+ $plugin load $format
+ set myplugin($format) $plugin
+ } else {
+ set plugin $myplugin($format)
+ }
+
+ return $plugin
+ }
+
+ method PluginSetup {mgr ip} {
+ # Inject a pseudo package into the plugin interpreter the
+ # formatters can use to check that they were loaded into a
+ # proper environment.
+ $ip eval {package provide doctools::toc::export::plugin 1}
+ return
+ }
+
+ # ### ### ### ######### ######### #########
+ ## State
+
+ # Array serving as a cache for the various plugin managers holding
+ # a specific export plugin.
+
+ variable myplugin -array {}
+
+ # A component managing the configuration given to the export
+ # plugins when they are invoked.
+
+ component myconfig -public config
+
+ ##
+ # ### ### ### ######### ######### #########
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::export 0.1
+return
diff --git a/tcllib/modules/doctools2toc/export.test b/tcllib/modules/doctools2toc/export.test
new file mode 100644
index 0000000..d5e3f9d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export.test
@@ -0,0 +1,212 @@
+# -*- tcl -*-
+# toc.test: tests for the doctools::toc package.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: export.test,v 1.2 2009/04/29 02:10:56 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2
+
+support {
+ use fileutil/fileutil.tcl fileutil ;# tests/common
+
+ use struct/list.tcl struct::list
+ use snit/snit.tcl snit
+ use log/logger.tcl logger
+ use pluginmgr/pluginmgr.tcl pluginmgr
+
+ use doctools2base/config.tcl doctools::config
+ useLocal structure.tcl doctools::toc::structure
+ use doctools2base/nroff_manmacros.tcl doctools::nroff::man_macros
+
+ source [tcllibPath doctools2base/tests/common]
+}
+testing {
+ useLocalKeep export.tcl doctools::toc::export
+}
+
+# -------------------------------------------------------------------------
+
+setup_plugins
+
+# -------------------------------------------------------------------------
+
+test doctools-toc-export-1.0 {export object, wrong#args} -setup {
+ doctools::toc::export E
+} -body {
+ E export object
+} -cleanup {
+ E destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::export::Snit_hmethodexport_object type selfns win self obj ?format?"}
+
+test doctools-toc-export-1.1 {export object, wrong#args} -setup {
+ doctools::toc::export E
+} -body {
+ E export object O F XXX
+} -cleanup {
+ E destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::export::Snit_hmethodexport_object type selfns win self obj ?format?"}
+
+test doctools-toc-export-2.0 {export serial, wrong#args} -setup {
+ doctools::toc::export E
+} -body {
+ E export serial
+} -cleanup {
+ E destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::export::Snit_hmethodexport_serial type selfns win self serial ?format?"}
+
+test doctools-toc-export-2.1 {export serial, wrong#args} -setup {
+ doctools::toc::export E
+} -body {
+ E export serial S F XXX
+} -cleanup {
+ E destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::export::Snit_hmethodexport_serial type selfns win self serial ?format?"}
+
+test doctools-toc-export-5.0 {config names, wrong#args} -setup {
+ doctools::toc::export E
+} -body {
+ E config names X
+} -cleanup {
+ E destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::config::Snit_methodnames type selfns win self"}
+
+test doctools-toc-export-6.0 {config get, wrong#args} -setup {
+ doctools::toc::export E
+} -body {
+ E config get X
+} -cleanup {
+ E destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::config::Snit_methodget type selfns win self"}
+
+test doctools-toc-export-7.0 {config set, wrong#args} -setup {
+ doctools::toc::export E
+} -body {
+ E config set
+} -cleanup {
+ E destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::config::Snit_methodset type selfns win self name ?value?"}
+
+test doctools-toc-export-7.1 {config set, wrong#args} -setup {
+ doctools::toc::export E
+} -body {
+ E config set N V X
+} -cleanup {
+ E destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::config::Snit_methodset type selfns win self name ?value?"}
+
+# -------------------------------------------------------------------------
+
+test doctools-toc-export-12.0 {config set, define single var} -setup {
+ doctools::toc::export E
+} -body {
+ E config set N V
+ E config get
+} -cleanup {
+ E destroy
+} -result {N V}
+
+test doctools-toc-export-12.1 {config set, define multiple vars} -setup {
+ doctools::toc::export E
+} -body {
+ E config set N V
+ E config set A B
+ dictsort [E config get]
+} -cleanup {
+ E destroy
+} -result {A B N V}
+
+test doctools-toc-export-12.2 {config set, as query} -setup {
+ doctools::toc::export E
+ E config set N V
+} -body {
+ E config set N
+} -cleanup {
+ E destroy
+} -result V
+
+test doctools-toc-export-13.0 {config unset, all} -setup {
+ doctools::toc::export E
+ E config set N V
+} -body {
+ E config unset
+ E config get
+} -cleanup {
+ E destroy
+} -result {}
+
+test doctools-toc-export-13.1 {config unset, by exact name} -setup {
+ doctools::toc::export E
+ E config set N V
+ E config set A B
+} -body {
+ E config unset N
+ E config get
+} -cleanup {
+ E destroy
+} -result {A B}
+
+test doctools-toc-export-13.2 {config unset, by glob pattern} -setup {
+ doctools::toc::export E
+ E config set N V
+ E config set N' V'
+ E config set A B
+} -body {
+ E config unset N*
+ E config get
+} -cleanup {
+ E destroy
+} -result {A B}
+
+test doctools-toc-export-14.0 {config names, empty} -setup {
+ doctools::toc::export E
+} -body {
+ E config names
+} -cleanup {
+ E destroy
+} -result {}
+
+test doctools-toc-export-14.1 {config names, with variables} -setup {
+ doctools::toc::export E
+ E config set N V
+ E config set A B
+} -body {
+ lsort -dict [E config names]
+} -cleanup {
+ E destroy
+} -result {A N}
+
+test doctools-toc-export-15.0 {config get, empty} -setup {
+ doctools::toc::export E
+} -body {
+ E config get
+} -cleanup {
+ E destroy
+} -result {}
+
+test doctools-toc-export-15.1 {config get, with variables} -setup {
+ doctools::toc::export E
+ E config set N V
+ E config set A B
+} -body {
+ dictsort [E config get]
+} -cleanup {
+ E destroy
+} -result {A B N V}
+
+# toc_export tests, numbering starts at 20
+# -------------------------------------------------------------------------
+
+source [localPath tests/export]
+
+# -------------------------------------------------------------------------
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/export_doctoc.man b/tcllib/modules/doctools2toc/export_doctoc.man
new file mode 100644
index 0000000..f7ddd4d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_doctoc.man
@@ -0,0 +1,7 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE doctoc]
+[vset NAME doctoc]
+[vset REQUIRE null]
+[vset CONFIG doctoc]
+[vset VERSION 0.1]
+[include include/export/plugin.inc]
diff --git a/tcllib/modules/doctools2toc/export_doctoc.tcl b/tcllib/modules/doctools2toc/export_doctoc.tcl
new file mode 100644
index 0000000..27d6aa2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_doctoc.tcl
@@ -0,0 +1,217 @@
+# doctoc.tcl --
+#
+# The doctoc export plugin. Generation of doctoc markup.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: export_doctoc.tcl,v 1.3 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# This package is a plugin for the doctools::toc v2 system. It takes
+# the list serialization of a table of contens and produces text in
+# doctoc format.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: doctools::toc::export::plugin
+
+package require Tcl 8.4
+package require doctools::toc::export::plugin ; # Presence of this
+ # pseudo package
+ # indicates execution
+ # inside of a properly
+ # initialized plugin
+ # interpreter.
+package require doctools::toc::structure ; # Verification that
+ # the input is proper.
+
+# ### ### ### ######### ######### #########
+## API.
+
+proc export {serial configuration} {
+
+ # Phase I. Check that we got a canonical ToC serialization. That
+ # makes the unpacking easier, as we can mix it with the
+ # generation of the output, knowing that everything is
+ # already sorted as it should be.
+
+ ::doctools::toc::structure verify-as-canonical $serial
+
+ # ### ### ### ######### ######### #########
+ # Configuration ...
+ # * Standard entries
+ # - user = person running the application doing the formatting
+ # - format = name of this format
+ # - file = name of the file the ToC came from. Optional.
+ # - map = maps symbolic document ids to actual file path or url. Optional.
+ # * doctoc specific entries
+ # - newlines = boolean. tags separated by eol markers
+ # - indented = boolean. tags indented per the toc structure.
+ # - aligned = boolean. reference information tabular aligned within keys.
+ #
+ # Notes
+ # * This format ignores 'map' even if set, as the written doctoc
+ # contains the symbolic document ids and only them.
+ # * aligned => newlines
+ # * indented => newlines
+
+ # Combinations of the format specific entries
+ # N I A |
+ # - - - + ---------------------
+ # 0 0 0 | Ultracompact (no whitespace, single line)
+ # 1 0 0 | Compact (no whitespace, multiple lines)
+ # 1 1 0 | Indented
+ # 1 0 1 | Tabular aligned references
+ # 1 1 1 | Indented + Tabular aligned references
+ # - - - + ---------------------
+ # 0 1 0 | Not possible, per the implications above.
+ # 0 0 1 | ditto
+ # 0 1 1 | ditto
+ # - - - + ---------------------
+
+ # Import the configuration and initialize the internal state
+ array set config {
+ newlines 0
+ aligned 0
+ indented 0
+ }
+ array set config $configuration
+
+ # Force the implications mentioned in the notes above.
+ if {
+ $config(aligned) ||
+ $config(indented)
+ } {
+ set config(newlines) 1
+ }
+
+ # ### ### ### ######### ######### #########
+
+ # Phase II. Generate the output, taking the configuration into
+ # account.
+
+ TagsBegin
+
+ # First some comments about the provenance of the output.
+ Tag+ comment [list "Generated @ [clock format [clock seconds]]"]
+ Tag+ comment [list "By $config(user)"]
+ if {[info exists config(file)] && ($config(file) ne {})} {
+ Tag+ comment [list "From file $config(file)"]
+ }
+
+ # Unpack the serialization.
+ array set toc $serial
+ array set toc $toc(doctools::toc)
+ unset toc(doctools::toc)
+
+ # Now open the markup
+
+ Tag+ toc_begin [list $toc(label) $toc(title)]
+ PrintItems $toc(items) { } { }
+ TagPrefix {}
+ Tag+ toc_end
+
+ # Last formatting, joining the commands together.
+ set sep [expr {$config(newlines) ? "\n" : ""}]
+ return [join $lines $sep]
+
+ # ### ### ### ######### ######### #########
+}
+
+# ### ### ### ######### ######### #########
+
+proc PrintItems {items indentation increment} {
+ upvar 1 config config prefix prefix lines lines
+
+ if {$config(aligned)} {
+ set imax 0
+ set lmax 0
+ foreach element $items {
+ foreach {etype edata} $element break
+ if {$etype eq "division"} { continue }
+ array set toc $edata
+ Max imax [list $toc(id)]
+ Max lmax [list $toc(label)]
+ unset toc
+ }
+ }
+
+ foreach element $items {
+ if {$config(indented)} {TagPrefix $indentation}
+ foreach {etype edata} $element break
+ array set toc $edata
+ switch -exact -- $etype {
+ reference {
+ if {$config(aligned)} {
+ Tag+ item [FmtR imax $toc(id)] [FmtR lmax $toc(label)] [list $toc(desc)]
+ } else {
+ Tag+ item [list $toc(id) $toc(label) $toc(desc)]
+ }
+ }
+ division {
+ if {[info exists toc(id)]} {
+ Tag+ division_start [list $toc(label) $toc(id)]
+ } else {
+ Tag+ division_start [list $toc(label)]
+ }
+ PrintItems $toc(items) $indentation$increment $increment
+ if {$config(indented)} {TagPrefix $indentation}
+ Tag+ division_end
+ }
+ }
+ unset toc
+ }
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+proc TagPrefix {str} {
+ upvar 1 prefix prefix
+ set prefix $str
+ return
+}
+
+proc TagsBegin {} {
+ upvar 1 prefix prefix lines lines
+ set prefix {}
+ set lines {}
+ return
+}
+
+proc Tag {n args} {
+ upvar 1 prefix prefix
+ set cmd $prefix
+ append cmd \[$n
+ if {[llength $args]} { append cmd " [join $args]" }
+ append cmd \]
+ return $cmd
+}
+
+proc Tag+ {n args} {
+ upvar 1 prefix prefix lines lines
+ lappend lines [eval [linsert $args 0 Tag $n]]
+ return
+}
+
+proc Max {v str} {
+ upvar 1 $v max
+ set x [string length $str]
+ if {$x <= $max} return
+ set max $x
+ return
+}
+
+proc FmtR {v str} {
+ upvar 1 $v max
+ return [list $str][string repeat { } [expr {$max - [string length [list $str]]}]]
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::export::doctoc 0.1
+return
diff --git a/tcllib/modules/doctools2toc/export_doctoc.test b/tcllib/modules/doctools2toc/export_doctoc.test
new file mode 100644
index 0000000..55ad846
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_doctoc.test
@@ -0,0 +1,77 @@
+# -*- tcl -*-
+# toc_export_doctoc.test: tests for the doctools::toc::export::doctoc package/plugin.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: export_doctoc.test,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ use fileutil/fileutil.tcl fileutil ;# tests/common
+ useLocal structure.tcl doctools::toc::structure
+}
+testing {
+ package provide doctools::toc::export::plugin 1
+ # The above fakes the export plugin environment.
+
+ useLocal export_doctoc.tcl doctools::toc::export::doctoc
+}
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+
+# General set of error cases regarding the number of arguments.
+
+test doctools-toc-export-doctoc-1.0 {export, wrong#args} -body {
+ export
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-doctoc-1.1 {export, wrong#args} -body {
+ export S
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-doctoc-1.2 {export, wrong#args} -body {
+ export S C XXX
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+# -------------------------------------------------------------------------
+
+# Testing the generation of doctoc output, from toc serialization,
+# for all possible plugin configurations.
+
+foreach {k nl in al name} {
+ 0 0 0 0 ultracompact
+ 1 1 0 0 compact
+ 2 1 1 0 indented
+ 3 1 0 1 aligned
+ 4 1 1 1 indalign
+ 5 0 1 0 indented
+ 6 0 0 1 aligned
+ 7 0 1 1 indalign
+} {
+ TestFilesProcess $mytestdir ok serial doctoc-$name -> n label input data expected {
+ test doctools-toc-export-doctoc-2.$k.$n "doctools::toc::export::doctoc, ${label}-$name, ok" -setup {
+ set configuration [list newlines $nl indented $in aligned $al user _dummy_]
+ } -body {
+ stripcomments [export $data $configuration]
+ } -cleanup {
+ unset configuration
+ } -result $expected
+ }
+}
+
+#----------------------------------------------------------------------
+unset n label input data expected
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/export_html.tcl b/tcllib/modules/doctools2toc/export_html.tcl
new file mode 100644
index 0000000..bfdbeed
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_html.tcl
@@ -0,0 +1,323 @@
+# text.tcl --
+#
+# The HTML export plugin. Generation of HTML markup.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: export_html.tcl,v 1.3 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# This package is a plugin for the doctools::toc v2 system. It takes
+# the list serialization of a table of contents and produces text in
+# HTML format.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: doctools::toc::export::plugin
+
+package require Tcl 8.4
+package require doctools::toc::export::plugin ; # Presence of this
+ # pseudo package
+ # indicates execution
+ # inside of a properly
+ # initialized plugin
+ # interpreter.
+package require doctools::toc::structure ; # Verification that the
+ # input is proper.
+package require doctools::html
+package require doctools::html::cssdefaults
+
+doctools::html::import ;# -> ::html::*
+
+# ### ### ### ######### ######### #########
+## API.
+
+proc export {serial configuration} {
+
+ # Phase I. Check that we got a canonical toc serialization. That
+ # makes the unpacking easier, as we can mix it with the
+ # generation of the output, knowing that everything is
+ # already sorted as it should be.
+
+ ::doctools::toc::structure verify-as-canonical $serial
+
+ # ### ### ### ######### ######### #########
+ # Configuration ...
+ # * Standard entries
+ # - user = person running the application doing the formatting
+ # - format = name of this format
+ # - file = name of the file the toc came from. Optional.
+ # - map = maps symbolic references to actual file path. Optional.
+
+ # * HTML specific entries
+ # - newlines = boolean. tags separated by eol markers
+ # - indented = boolean. tags indented per their nesting structure.
+ # //layout = string in { list, table }.
+ #
+ # - meta = HTML fragment for use within the document <meta> section.
+ # - header = HTML fragment used immediately after <body>
+ # - footer = HTML fragment used immediately before </body>
+ #
+ # - rid = dictionary mapping element labels to link anchor names.
+ # <=> Reference IDentifier
+ #
+ # Notes
+ # * indented => newlines
+
+ # Import the configuration and initialize the internal state
+ #// layout list
+ array set config {
+ newlines 0
+ indented 0
+ meta {}
+ header {}
+ footer {}
+ rid {}
+ map {}
+ sepline ------------------------------------------------------------
+ class.main doctools
+ class.header toc-header
+ class.title toc-title
+ class.navsep toc-navsep
+ class.contents toc-contents
+ class.ref toc-ref
+ class.div toc-div
+ class.footer toc-footer
+ }
+ array set config $configuration
+ array set map $config(map)
+ array set rid $config(rid)
+
+ # Force the implications mentioned in the notes above.
+ if {$config(indented)} {
+ set config(newlines) 1
+ }
+
+ # Allow structuring comments iff structure is present.
+ set config(comments) [expr {$config(indented) || $config(newlines)}]
+
+ # ### ### ### ######### ######### #########
+
+ # Phase II. Generate the output, taking the configuration into
+ # account.
+
+ # Unpack the serialization.
+ array set toc $serial
+ array set toc $toc(doctools::toc)
+ unset toc(doctools::toc)
+
+ html::begin
+ # Configure the layouting
+ if {!$config(indented)} { html::indenting 0 }
+ if {!$config(newlines)} { html::newlines 0 }
+
+ html::tag* html {
+ html::newline ; html::indented 4 {
+ Header
+ Provenance
+ Body
+ }
+ }
+
+ return [html::done]
+}
+
+# ### ### ### ######### ######### #########
+
+proc Header {} {
+ upvar 1 config config toc toc
+ html::tag* head {
+ html::newline ; html::indented 4 {
+ html::tag= title [Title] ; html::newline
+ if {![Extend meta]} {
+ html::tag* style {
+ DefaultStyle
+ } ; html::newline
+ }
+ }
+ } ; html::newline
+ return
+}
+
+proc Provenance {} {
+ upvar 1 config config
+ if {!$config(comments)} return
+ html::comment [html::collect {
+ html::indented 4 {
+ html::+ "Generated @ [clock format [clock seconds]]" ; html::newline
+ html::+ "By $config(user)" ; html::newline
+ if {[info exists config(file)] && ($config(file) ne {})} {
+ html::+ "From file $config(file)" ; html::newline
+ }
+ }
+ }] ; html::newline
+ return
+}
+
+proc Body {} {
+ upvar 1 config config rid rid toc toc
+ html::tag* body {
+ html::newline ; html::indented 4 {
+ html::tag* div class $config(class.main) {
+ html::newline ; html::indented 4 {
+ html::tag* div class $config(class.header) {
+ html::newline ; html::indented 4 {
+ BodyTitle
+ UserHeader
+ html::tag1 hr class $config(class.navsep) ; html::newline
+ }
+ } ; html::newline
+ Division $toc(items) {} {Table Of Contents}
+ html::tag* div class $config(class.footer) {
+ html::newline ; html::indented 4 {
+ html::tag1 hr class $config(class.navsep) ; html::newline
+ UserFooter
+ }
+ } ; html::newline
+ }
+ } ; html::newline
+ }
+ } ; html::newline
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+proc BodyTitle {} {
+ upvar 1 toc toc config config
+ html::tag= h1 class $config(class.title) [Title] ; html::newline
+ return
+}
+
+proc UserHeader {} {
+ upvar 1 config config
+ Extend header
+ html::newline
+ return
+}
+
+proc UserFooter {} {
+ upvar 1 config config
+ Extend footer
+ html::newline
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+proc Title {} {
+ upvar 1 toc(label) label toc(title) title
+ if {($label ne {}) && ($title ne {})} {
+ return "$label -- $title"
+ } elseif {$label ne {}} {
+ return $label
+ } elseif {$title ne {}} {
+ return $title
+ }
+ return -code error {Reached the unreachable}
+}
+
+proc DefaultStyle {} {
+ html::comment \n[doctools::html::cssdefaults::contents]
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+proc Division {items path seplabel} {
+ upvar 1 config config rid rid map map
+
+ # No content for an empty division
+ if {![llength $items]} return
+
+ # Process the elements in a division.
+
+ Separator "Start $seplabel"
+
+ html::tag* dl class $config(class.contents) {
+ html::newline ; html::indented 4 {
+ foreach element $items {
+ foreach {etype edata} $element break
+ array set e $edata
+ switch -exact -- $etype {
+ reference {
+ html::tag* dt class $config(class.ref) {
+ RMap $e(label)
+ html::tag= a href [Map $e(id)] $e(label)
+ }
+ html::newline
+ html::tag= dd class $config(class.ref) $e(desc)
+ html::newline
+ }
+ division {
+ html::tag* dt class $config(class.div) {
+ RMap $e(label)
+ if {[info exists e(id)]} {
+ html::tag= a href [Map $e(id)] $e(label)
+ } else {
+ html::+ $e(label)
+ }
+ }
+ html::newline
+ html::tag* dd class $config(class.div) {
+ html::newline ; html::indented 4 {
+ Division $e(items) [linsert $path end $e(label)] "Division ($e(label))"
+ }
+ } ; html::newline
+ }
+ }
+ unset e
+ }
+ }
+ } ; html::newline
+ Separator "Stop $seplabel"
+}
+
+# ### ### ### ######### ######### #########
+
+proc Separator {{text {}}} {
+ upvar config config
+ if {!$config(comments)} return
+ set str $config(sepline)
+ if {$text ne {}} {
+ set new " $text "
+ set str [string replace $str 1 [string length $new] $new]
+ }
+ html::comment $str
+ html::newline
+ return
+}
+
+proc Map {id} {
+ upvar 1 map map
+ if {![info exists map($id)]} { return $id }
+ return $map($id)
+}
+
+proc RMap {label} {
+ upvar 1 rid rid path path
+ set k [linsert $path end $label]
+ if {![info exists rid($k)]} return
+ html::tag/ a name $rid($k)
+}
+
+proc Extend {varname} {
+ upvar 1 config config
+ if {$config($varname) eq {}} {
+ if {$config(comments)} {
+ html::comment "Customization Point: $varname"
+ }
+ return 0
+ }
+ html::+++ $config($varname)
+ return 1
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::export::html 0.1
+return
diff --git a/tcllib/modules/doctools2toc/export_html.test b/tcllib/modules/doctools2toc/export_html.test
new file mode 100644
index 0000000..d5f2f30
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_html.test
@@ -0,0 +1,76 @@
+# -*- tcl -*-
+# toc_export_html.test: tests for the doctools::toc::export::html package/plugin.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: export_html.test,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ use fileutil/fileutil.tcl fileutil ;# tests/common
+ useLocal structure.tcl doctools::toc::structure
+ use doctools2base/text.tcl doctools::text
+ use doctools2base/html.tcl doctools::html
+ use doctools2base/html_cssdefaults.tcl doctools::html::cssdefaults
+}
+testing {
+ package provide doctools::toc::export::plugin 1
+ # The above fakes the export plugin environment.
+
+ useLocal export_html.tcl doctools::toc::export::html
+}
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+
+# General set of error cases regarding the number of arguments.
+
+test doctools-toc-export-html-1.0 {export, wrong#args} -body {
+ export
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-html-1.1 {export, wrong#args} -body {
+ export S
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-html-1.2 {export, wrong#args} -body {
+ export S C XXX
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+# -------------------------------------------------------------------------
+
+# Testing the generation of html output, from toc serialization,
+# for all possible plugin configurations.
+
+foreach {k nl in section} {
+ 0 0 0 -ultracompact
+ 1 0 1 -indented
+ 2 1 0 -compact
+ 3 1 1 -indented
+} {
+ TestFilesProcess $mytestdir ok serial html$section -> n label input data expected {
+ test doctools-toc-export-html-2.$k.$n "doctools::toc::export::html, $label$section, ok" -setup {
+ set configuration [list newlines $nl indented $in user _dummy_]
+ } -body {
+ striphtmlcomments [export $data $configuration] 3
+ } -cleanup {
+ unset configuration
+ } -result $expected
+ }
+}
+
+#----------------------------------------------------------------------
+unset n label input data expected
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/export_json.tcl b/tcllib/modules/doctools2toc/export_json.tcl
new file mode 100644
index 0000000..7051f59
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_json.tcl
@@ -0,0 +1,223 @@
+# json.tcl --
+#
+# The JSON export plugin. Generation of Java Script Object Notation.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: export_json.tcl,v 1.3 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# This package is a plugin for the doctools::toc v2 system. It takes
+# the list serialization of a table of contents and produces text in
+# JSON format.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: doctools::toc::export::plugin
+
+package require Tcl 8.4
+package require doctools::toc::export::plugin ; # Presence of this
+ # pseudo package
+ # indicates execution
+ # inside of a properly
+ # initialized plugin
+ # interpreter.
+package require doctools::toc::structure ; # Verification that
+ # the input is proper.
+package require textutil::adjust
+
+# ### ### ### ######### ######### #########
+## API.
+
+proc export {serial configuration} {
+
+ # Phase I. Check that we got a canonical toc serialization. That
+ # makes the unpacking easier, as we can mix it with the
+ # generation of the output, knowing that everything is
+ # already sorted as it should be.
+
+ ::doctools::toc::structure verify-as-canonical $serial
+
+ # ### ### ### ######### ######### #########
+ # Configuration ...
+ # * Standard entries
+ # - user = person running the application doing the formatting
+ # - format = name of this format
+ # - file = name of the file the toc came from. Optional.
+ # - map = maps symbolic references to actual file path. Optional.
+ # * json/format specific entries
+ # - indented = boolean. objects indented per the toc structure.
+ # - aligned = boolean. object keys tabular aligned vertically.
+ #
+ # Notes
+ # * This format ignores 'map' even if set, as the written json
+ # contains the symbolic references and only them.
+ # * aligned => indented
+
+ # Combinations of the format specific entries
+ # N I A |
+ # - - - + ---------------------
+ # 0 0 0 | Ultracompact (no whitespace, single line)
+ # 1 0 0 | Compact (no whitespace, multiple lines)
+ # 1 1 0 | Indented
+ # 1 0 1 | Tabular aligned references
+ # 1 1 1 | Indented + Tabular aligned references
+ # - - - + ---------------------
+ # 0 1 0 | Not possible, per the implications above.
+ # 0 0 1 | ditto
+ # 0 1 1 | ditto
+ # - - - + ---------------------
+
+ # Import the configuration and initialize the internal state
+ array set config {
+ indented 0
+ aligned 0
+ }
+ array set config $configuration
+
+ # Force the implications mentioned in the notes above.
+ if {$config(aligned)} {
+ set config(indented) 1
+ }
+
+ # ### ### ### ######### ######### #########
+
+ # Phase II. Generate the output, taking the configuration into
+ # account. We construct this from the inside out.
+
+ # Unpack the serialization.
+ array set toc $serial
+ array set toc $toc(doctools::toc)
+ unset toc(doctools::toc)
+
+ return [JsonObject doctools::toc \
+ [JsonObject \
+ items [ProcessDivision $toc(items)] \
+ label [JsonString $toc(label)] \
+ title [JsonString $toc(title)]]]
+
+ # ### ### ### ######### ######### #########
+}
+
+proc ProcessDivision {items} {
+ upvar 1 config config
+ set result {}
+
+ foreach element $items {
+ foreach {etype edata} $element break
+ array set toc $edata
+ switch -exact -- $etype {
+ reference {
+ set edata [JsonObject \
+ desc [JsonString $toc(desc)] \
+ id [JsonString $toc(id)] \
+ label [JsonString $toc(label)]]
+ }
+ division {
+ set edata {}
+ if {[info exists toc(id)]} { lappend edata id [JsonString $toc(id)] }
+ lappend edata \
+ items [ProcessDivision $toc(items)] \
+ label [JsonString $toc(label)]
+ set edata [JsonObjectDict $edata]
+ }
+ }
+ unset toc
+ lappend result [JsonObject $etype $edata]
+ }
+
+ return [JsonArrayList $result]
+}
+
+# ### ### ### ######### ######### #########
+
+proc JsonQuotes {} {
+ return [list "\"" "\\\"" / \\/ \\ \\\\ \b \\b \f \\f \n \\n \r \\r \t \\t]
+}
+
+proc JsonString {s} {
+ return "\"[string map [JsonQuotes] $s]\""
+}
+
+proc JsonArray {args} {
+ upvar 1 config config
+ return [JsonArrayList $args]
+}
+
+proc JsonArrayList {list} {
+ # compact form.
+ return "\[[join $list ,]\]"
+}
+
+proc JsonObject {args} {
+ upvar 1 config config
+ return [JsonObjectDict $args]
+}
+
+proc JsonObjectDict {dict} {
+ # The dict maps string keys to json-formatted data. I.e. we have
+ # to quote the keys, but not the values, as the latter are already
+ # in the proper format.
+ upvar 1 config config
+
+ set tmp {}
+ foreach {k v} $dict { lappend tmp [JsonString $k] $v }
+ set dict $tmp
+
+ if {$config(aligned)} { Align $dict max }
+
+ if {$config(indented)} {
+ set content {}
+ foreach {k v} $dict {
+ if {$config(aligned)} { set k [FmtR max $k] }
+ if {[string match *\n* $v]} {
+ # multi-line value
+ lappend content " $k : [textutil::adjust::indent $v { } 1]"
+ } else {
+ # single line value.
+ lappend content " $k : $v"
+ }
+ }
+ if {[llength $content]} {
+ return "\{\n[join $content ,\n]\n\}"
+ } else {
+ return "\{\}"
+ }
+ } else {
+ # ultra compact form.
+ set tmp {}
+ foreach {k v} $dict { lappend tmp "$k:$v" }
+ return "\{[join $tmp ,]\}"
+ }
+}
+
+proc Align {dict mv} {
+ upvar 1 $mv max
+ # Generate a list of references sortable by name, and also find the
+ # max length of all relevant names.
+ set max 0
+ foreach {str _} $dict { Max max $str }
+ return
+}
+
+proc Max {v str} {
+ upvar 1 $v max
+ set x [string length $str]
+ if {$x <= $max} return
+ set max $x
+ return
+}
+
+proc FmtR {v str} {
+ upvar 1 $v max
+ return $str[string repeat { } [expr {$max - [string length $str]}]]
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::export::json 0.1
+return
diff --git a/tcllib/modules/doctools2toc/export_json.test b/tcllib/modules/doctools2toc/export_json.test
new file mode 100644
index 0000000..dc9c772
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_json.test
@@ -0,0 +1,74 @@
+# -*- tcl -*-
+# toc_export_json.test: tests for the doctools::toc::export::json package/plugin.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: export_json.test,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ use fileutil/fileutil.tcl fileutil ;# tests/common
+ use textutil/adjust.tcl textutil::adjust
+ useLocal structure.tcl doctools::toc::structure
+}
+testing {
+ package provide doctools::toc::export::plugin 1
+ # The above fakes the export plugin environment.
+
+ useLocal export_json.tcl doctools::toc::export::json
+}
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+
+# General set of error cases regarding the number of arguments.
+
+test doctools-toc-export-json-1.0 {export, wrong#args} -body {
+ export
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-json-1.1 {export, wrong#args} -body {
+ export S
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-json-1.2 {export, wrong#args} -body {
+ export S C XXX
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+# -------------------------------------------------------------------------
+
+# Testing the generation of json output, from toc serialization,
+# for all possible plugin configurations.
+
+foreach {k in al section} {
+ 0 0 0 -ultracompact
+ 1 1 0 -indented
+ 2 0 1 -indalign
+ 3 1 1 -indalign
+} {
+ TestFilesProcess $mytestdir ok serial json$section -> n label input data expected {
+ test doctools-toc-export-json-2.$k.$n "doctools::toc::export::json, $label$section, ok" -setup {
+ set configuration [list indented $in aligned $al]
+ } -body {
+ export $data $configuration
+ } -cleanup {
+ unset configuration
+ } -result $expected
+ }
+}
+
+#----------------------------------------------------------------------
+unset n label input data expected
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/export_nroff.tcl b/tcllib/modules/doctools2toc/export_nroff.tcl
new file mode 100644
index 0000000..28a7d66
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_nroff.tcl
@@ -0,0 +1,218 @@
+# text.tcl --
+#
+# The NROFF export plugin. Generation of man.macros based nroff markup.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: export_nroff.tcl,v 1.4 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# This package is a plugin for the doctools::toc v2 system. It takes
+# the list serialization of a table of contents and produces text in
+# nroff format, man.macros based.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: doctools::toc::export::plugin
+
+package require Tcl 8.4
+package require doctools::toc::export::plugin ; # Presence of this
+ # pseudo package
+ # indicates execution
+ # inside of a properly
+ # initialized plugin
+ # interpreter.
+package require doctools::toc::structure ; # Verification that the
+ # input is proper.
+package require doctools::text ; # Text assembly package
+package require doctools::nroff::man_macros ; # Macro definitions for result.
+
+doctools::text::import ;# -> ::text::*
+
+# ### ### ### ######### ######### #########
+## API.
+
+proc export {serial configuration} {
+
+ # Phase I. Check that we got a canonical toc serialization. That
+ # makes the unpacking easier, as we can mix it with the
+ # generation of the output, knowing that everything is
+ # already sorted as it should be.
+
+ ::doctools::toc::structure verify-as-canonical $serial
+
+ # ### ### ### ######### ######### #########
+ # Configuration ...
+ # * Standard entries
+ # - user = person running the application doing the formatting
+ # - format = name of this format
+ # - file = name of the file the toc came from. Optional.
+ # - map = maps symbolic references to actual file path. Ignored
+ #
+ # Specific
+ # - inline = boolean. if set (default) man.macros is inlined in
+ # the output. other a .so reference to the file is
+ # generated.
+
+ # Import the configuration and initialize the internal state
+
+ array set config {
+ inline 1
+ }
+ array set config $configuration
+
+ # ### ### ### ######### ######### #########
+
+ # Phase II. Generate the output, taking the configuration into
+ # account.
+
+ # Unpack the serialization.
+ array set toc $serial
+ array set toc $toc(doctools::toc)
+ unset toc(doctools::toc)
+
+ text::begin
+ text::indenting 0 ; # Just in case someone tries to.
+
+ Provenance
+ if {$config(inline)} {
+ text::newline?
+ text::+ [doctools::nroff::man_macros::contents]
+ } else {
+ .so man.macros
+ }
+ .TH $toc(label)
+ .SH {table of contents}
+ if {$toc(title) ne {}} {
+ text::+ $toc(title)
+ }
+
+ Division $toc(items)
+ return [text::done]
+}
+
+proc Division {items} {
+ if {![llength $items]} return
+ .RS
+
+ foreach element $items {
+ foreach {etype edata} $element break
+ array set e $edata
+ switch -exact -- $etype {
+ reference {
+ .TP [BOLD $e(label)]
+ text::newline
+ text::+ $e(desc)
+ text::newline
+ }
+ division {
+ .TP [BOLD $e(label)]
+ text::newline
+ Division $e(items)
+ }
+ }
+ unset e
+ }
+ .RE
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+proc Provenance {} {
+ upvar 1 config config
+ COMMENT "Generated @ [clock format [clock seconds]]"
+ COMMENT "By $config(user)"
+ if {[info exists config(file)] && ($config(file) ne {})} {
+ COMMENT "From file $config(file)"
+ }
+ return
+}
+
+proc .so {file} {
+ text::newline?
+ text::+ ".so $file"
+ text::newline
+ return
+}
+
+proc .TP {text} {
+ text::newline?
+ text::+ .TP
+ text::newline
+ text::+ $text
+ return
+}
+
+proc COMMENT {text} {
+ set pfx "'\\\" " ;#
+ text::newline?
+
+ foreach line [split $text \n] {
+ text::+ $pfx
+ text::+ $line
+ text::newline
+ }
+ #text::+ $pfx[join [split $text \n] \n$pfx]
+ return
+}
+
+proc BOLD {text} {
+ return \\fB$text\\fR
+}
+
+proc .RS {} {
+ text::newline?
+ text::+ .RS
+ text::newline
+ return
+}
+
+proc .RE {} {
+ text::newline?
+ text::+ .RE
+ text::newline
+ return
+}
+
+proc .PP {} {
+ text::newline?
+ text::+ .PP
+ text::newline
+ return
+}
+
+proc .SH {name} {
+ text::newline?
+ text::+ ".SH "
+ set hasspaces [regexp {[ ]} $name]
+ set name [string toupper $name]
+
+ if {$hasspaces} { text::+ \" }
+ text::+ $name
+ if {$hasspaces} { text::+ \" }
+ text::newline
+ return
+}
+
+proc .TH {name} {
+ text::newline?
+ text::+ ".TH "
+ set hasspaces [regexp {[ ]} $name]
+ set name [string toupper $name]
+
+ if {$hasspaces} { text::+ \" }
+ text::+ $name
+ if {$hasspaces} { text::+ \" }
+ text::newline
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::export::nroff 0.2
+return
diff --git a/tcllib/modules/doctools2toc/export_nroff.test b/tcllib/modules/doctools2toc/export_nroff.test
new file mode 100644
index 0000000..bae5dd3
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_nroff.test
@@ -0,0 +1,73 @@
+# -*- tcl -*-
+# toc_export_nroff.test: tests for the doctools::toc::export::nroff package/plugin.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: export_nroff.test,v 1.3 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ use fileutil/fileutil.tcl fileutil ;# tests/common
+ useLocal structure.tcl doctools::toc::structure
+ use doctools2base/text.tcl doctools::text
+ use doctools2base/nroff_manmacros.tcl doctools::nroff::man_macros
+}
+testing {
+ package provide doctools::toc::export::plugin 1
+ # The above fakes the export plugin environment.
+
+ useLocal export_nroff.tcl doctools::toc::export::nroff
+}
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+
+# General set of error cases regarding the number of arguments.
+
+test doctools-toc-export-nroff-1.0 {export, wrong#args} -body {
+ export
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-nroff-1.1 {export, wrong#args} -body {
+ export S
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-nroff-1.2 {export, wrong#args} -body {
+ export S C XXX
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+# -------------------------------------------------------------------------
+
+# Testing the generation of nroff output, from toc serialization,
+# for all possible plugin configurations.
+
+foreach {k inline section} {
+ 0 0 -external
+ 1 1 -inlined
+} {
+ TestFilesProcess $mytestdir ok serial nroff$section -> n label input data expected {
+ test doctools-toc-export-nroff-2.$k.$n "doctools::toc::export::nroff, $label$section, ok" -setup {
+ set configuration [list inline $inline user _dummy_]
+ } -body {
+ stripnroffcomments [stripmanmacros [export $data $configuration]]
+ } -cleanup {
+ unset configuration
+ } -result $expected
+ }
+}
+
+#----------------------------------------------------------------------
+unset n label input data expected
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/export_text.tcl b/tcllib/modules/doctools2toc/export_text.tcl
new file mode 100644
index 0000000..41a2864
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_text.tcl
@@ -0,0 +1,142 @@
+# text.tcl --
+#
+# The text export plugin. Generation of plain text (ReST -
+# re-structured text).
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: export_text.tcl,v 1.3 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# This package is a plugin for the the doctools::toc v2 system. It
+# takes the list serialization of a table of contents and produces
+# text in text format.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: doctools::toc::export::plugin
+
+package require Tcl 8.4
+package require doctools::toc::export::plugin ; # Presence of this
+ # pseudo package
+ # indicates execution
+ # inside of a properly
+ # initialized plugin
+ # interpreter.
+package require doctools::toc::structure ; # Verification that the
+ # input is proper.
+package require doctools::text ; # Text assembly package
+
+doctools::text::import ;# -> ::text::*
+
+# ### ### ### ######### ######### #########
+## API.
+
+proc export {serial configuration} {
+
+ # Phase I. Check that we got a canonical toc serialization. That
+ # makes the unpacking easier, as we can mix it with the
+ # generation of the output, knowing that everything is
+ # already sorted as it should be.
+
+ ::doctools::toc::structure verify-as-canonical $serial
+
+ # ### ### ### ######### ######### #########
+ # Configuration ...
+ # * Standard entries
+ # - user = person running the application doing the formatting
+ # - format = name of this format
+ # - file = name of the file the toc came from. Optional.
+ # - map = maps symbolic references to actual file path. Optional.
+
+ # //possible parameters to influence the output.
+ # //* symbolic mapping off/on
+
+ # Import the configuration and initialize the internal state
+
+ array set config $configuration
+ array set map {}
+ if {[info exists config(map)]} {
+ array set map $config(map)
+ }
+
+ # ### ### ### ######### ######### #########
+
+ # Phase II. Generate the output, taking the configuration into
+ # account.
+
+ # Unpack the serialization.
+ array set toc $serial
+ array set toc $toc(doctools::toc)
+ unset toc(doctools::toc)
+
+ text::begin
+ text::+ [Header]
+ text::underline =
+
+ # Iterate over the keys and their references
+ PrintDivision $toc(items)
+
+ # Return final assembled text
+ return [text::done]
+}
+
+proc PrintDivision {items} {
+ foreach element $items {
+ foreach {etype edata} $element break
+ array set toc $edata
+
+ switch -exact -- $etype {
+ reference {
+ text::newline
+ text::+ "[Map $toc(id)] : $toc(label)"
+ text::newline
+ text::indented 4 { text::+ $toc(desc) }
+ text::newline
+ }
+ division {
+ text::newline
+ if {[info exists toc(id)]} {
+ text::+ "[Map $toc(id)] : $toc(label)"
+ } else {
+ text::+ "$toc(label)"
+ }
+ text::underline -
+ text::indented 4 {
+ PrintDivision $toc(items)
+ }
+ text::newline
+ }
+ }
+ }
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+proc Header {} {
+ upvar 1 toc(label) label toc(title) title
+ if {($label ne {}) && ($title ne {})} {
+ return "$label -- $title"
+ } elseif {$label ne {}} {
+ return $label
+ } elseif {$title ne {}} {
+ return $title
+ }
+ return -code error {Reached the unreachable}
+}
+
+proc Map {id} {
+ upvar 1 map map
+ if {![info exists map($id)]} { return $id }
+ return $map($id)
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::export::text 0.1
+return
diff --git a/tcllib/modules/doctools2toc/export_text.test b/tcllib/modules/doctools2toc/export_text.test
new file mode 100644
index 0000000..dd5383f
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_text.test
@@ -0,0 +1,63 @@
+# -*- tcl -*-
+# toc_export_text.test: tests for the doctools::toc::export::text package/plugin.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: export_text.test,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ use fileutil/fileutil.tcl fileutil ;# tests/common
+ useLocal structure.tcl doctools::toc::structure
+ use doctools2base/text.tcl doctools::text
+}
+testing {
+ package provide doctools::toc::export::plugin 1
+ # The above fakes the export plugin environment.
+
+ useLocal export_text.tcl doctools::toc::export::text
+}
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+
+# General set of error cases regarding the number of arguments.
+
+test doctools-toc-export-text-1.0 {export, wrong#args} -body {
+ export
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-text-1.1 {export, wrong#args} -body {
+ export S
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-text-1.2 {export, wrong#args} -body {
+ export S C XXX
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+# -------------------------------------------------------------------------
+
+# Testing the generation of text output, from toc serialization,
+# for all possible plugin configurations.
+
+TestFilesProcess $mytestdir ok serial text -> n label input data expected {
+ test doctools-toc-export-text-2.$n "doctools::toc::export::text, $label, ok" -body {
+ export $data {}
+ } -result $expected
+}
+
+#----------------------------------------------------------------------
+unset n label input data expected
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/export_wiki.tcl b/tcllib/modules/doctools2toc/export_wiki.tcl
new file mode 100644
index 0000000..0ced5cf
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_wiki.tcl
@@ -0,0 +1,144 @@
+# text.tcl --
+#
+# The wiki export plugin. Generation of plain text, ready for
+# use by the Tcler's Wiki
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: export_wiki.tcl,v 1.3 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# This package is a plugin for the the doctools::toc v2 system. It
+# takes the list serialization of a table of contents and produces
+# text in wiki format.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: doctools::toc::export::plugin
+
+package require Tcl 8.4
+package require doctools::toc::export::plugin ; # Presence of this
+ # pseudo package
+ # indicates execution
+ # inside of a properly
+ # initialized plugin
+ # interpreter.
+package require doctools::toc::structure ; # Verification that the
+ # input is proper.
+package require doctools::text ; # Text assembly package
+
+doctools::text::import ;# -> ::text
+
+# ### ### ### ######### ######### #########
+## API.
+
+proc export {serial configuration} {
+
+ # Phase I. Check that we got a canonical toc serialization. That
+ # makes the unpacking easier, as we can mix it with the
+ # generation of the output, knowing that everything is
+ # already sorted as it should be.
+
+ ::doctools::toc::structure verify-as-canonical $serial
+
+ # ### ### ### ######### ######### #########
+ # Configuration ...
+ # * Standard entries
+ # - user = person running the application doing the formatting
+ # - format = name of this format
+ # - file = name of the file the toc came from. Optional.
+ # - map = maps symbolic references to actual file path. Optional.
+
+ # //possible parameters to influence the output.
+ # //* symbolic mapping off/on
+
+ # Import the configuration and initialize the internal state
+
+ array set config $configuration
+ array set map {}
+ if {[info exists config(map)]} {
+ array set map $config(map)
+ }
+
+ # ### ### ### ######### ######### #########
+
+ # Phase II. Generate the output, taking the configuration into
+ # account.
+
+ # Unpack the serialization.
+ array set toc $serial
+ array set toc $toc(doctools::toc)
+ unset toc(doctools::toc)
+
+ # FUTURE :: Create wiki package on top of the text generator,
+ # providing encapsulated wiki commands.
+
+ text::begin
+ text::+ "**[Header]**"
+ text::newline
+
+ PrintDivision $toc(items) { *} *
+
+ # Last formatting, joining the lines together.
+ return [text::done]
+}
+
+proc PrintDivision {items indent increment} {
+ upvar 1 map map
+ foreach element $items {
+ foreach {etype edata} $element break
+ array set toc $edata
+ switch -exact -- $etype {
+ reference {
+ text::newline
+ text::+ "$indent [FormatReference] : $toc(desc)"
+ }
+ division {
+ if {[info exists toc(id)]} {
+ text::newline
+ text::+ "$indent [FormatReference]"
+ } else {
+ text::newline
+ text::+ "$indent $toc(label)"
+ }
+ PrintDivision $toc(items) $indent$increment $increment
+ }
+ }
+ unset toc
+ }
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+proc FormatReference {} {
+ upvar 1 map map toc toc
+ return "\[[Map $toc(id)]%|%$toc(label)\]"
+}
+
+proc Header {} {
+ upvar 1 toc(label) label toc(title) title
+ if {($label ne {}) && ($title ne {})} {
+ return "$label -- $title"
+ } elseif {$label ne {}} {
+ return $label
+ } elseif {$title ne {}} {
+ return $title
+ }
+ return -code error {Reached the unreachable}
+}
+
+proc Map {id} {
+ upvar 1 map map
+ if {![info exists map($id)]} { return $id }
+ return $map($id)
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::export::wiki 0.1
+return
diff --git a/tcllib/modules/doctools2toc/export_wiki.test b/tcllib/modules/doctools2toc/export_wiki.test
new file mode 100644
index 0000000..a0dfae4
--- /dev/null
+++ b/tcllib/modules/doctools2toc/export_wiki.test
@@ -0,0 +1,63 @@
+# -*- tcl -*-
+# toc_export_wiki.test: tests for the doctools::toc::export::wiki package/plugin.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: export_wiki.test,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ use fileutil/fileutil.tcl fileutil ;# tests/common
+ useLocal structure.tcl doctools::toc::structure
+ use doctools2base/text.tcl doctools::text
+}
+testing {
+ package provide doctools::toc::export::plugin 1
+ # The above fakes the export plugin environment.
+
+ useLocal export_wiki.tcl doctools::toc::export::wiki
+}
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+
+# General set of error cases regarding the number of arguments.
+
+test doctools-toc-export-wiki-1.0 {export, wrong#args} -body {
+ export
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-wiki-1.1 {export, wrong#args} -body {
+ export S
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+test doctools-toc-export-wiki-1.2 {export, wrong#args} -body {
+ export S C XXX
+} -returnCodes error -result {wrong # args: should be "export serial configuration"}
+
+# -------------------------------------------------------------------------
+
+# Testing the generation of wiki output, from toc serialization,
+# for all possible plugin configurations.
+
+TestFilesProcess $mytestdir ok serial wiki -> n label input data expected {
+ test doctools-toc-export-wiki-2.$n "doctools::toc::export::wiki, $label, ok" -body {
+ export $data {}
+ } -result $expected
+}
+
+#----------------------------------------------------------------------
+unset n label input data expected
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/import.tcl b/tcllib/modules/doctools2toc/import.tcl
new file mode 100644
index 0000000..16cc8dc
--- /dev/null
+++ b/tcllib/modules/doctools2toc/import.tcl
@@ -0,0 +1,191 @@
+# doctoc.tcl --
+#
+# Importing indices into other formats.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: import.tcl,v 1.3 2011/11/17 08:00:45 andreas_kupries Exp $
+
+# Each object manages a set of plugins for the conversion of keyword
+# indices into some textual representation. I.e. this object manages
+# the conversion to specialized serializations of keyword indices.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+package require Tcl 8.4
+package require doctools::config
+package require doctools::toc::structure
+package require doctools::paths
+package require pluginmgr
+package require snit
+
+# ### ### ### ######### ######### #########
+## API
+
+snit::type ::doctools::toc::import {
+
+ # ### ### ### ######### ######### #########
+ ## Options :: None
+
+ # ### ### ### ######### ######### #########
+ ## Creation, destruction.
+
+ constructor {} {
+ install myconfig using ::doctools::config ${selfns}::config
+ install myinclude using ::doctools::paths ${selfns}::include
+ return
+ }
+
+ destructor {
+ $myconfig destroy
+ $myinclude destroy
+ # Clear the cache of loaded import plugins.
+ foreach k [array names myplugin] {
+ $myplugin($k) destroy
+ }
+ return
+ }
+
+ # ### ### ### ######### ######### #########
+ ## Convert from other formats to the Tcl toc serialization
+
+ method {import object text} {obj text {format {}}} {
+ $obj deserialize [$self import text $text $format]
+ return
+ }
+
+ method {import object file} {obj path {format {}}} {
+ $obj deserialize [$self import file $path $format]
+ return
+ }
+
+ # ### ### ### ######### ######### #########
+
+ method {import text} {text {format {}}} {
+ set plugin [$self GetPlugin $format]
+
+ set configuration [$myconfig get]
+ lappend configuration user $::tcl_platform(user)
+ lappend configuraton format [$plugin plugin]
+
+ return [$plugin do import $text $configuration]
+ }
+
+ method {import file} {path {format {}}} {
+ # The plugin is not trusted to handle the file to convert.
+ return [$self import text [fileutil::cat $path] $format]
+ }
+
+ # ### ### ### ######### ######### #########
+ ## Internal methods
+
+ method GetPlugin {format} {
+ if {$format eq {}} { set format doctoc }
+
+ if {![info exists myplugin($format)]} {
+ set plugin [pluginmgr ${selfns}::fmt-$format \
+ -pattern doctools::toc::import::* \
+ -api { import } \
+ -setup [mymethod PluginSetup]]
+ ::pluginmgr::paths $plugin doctools::toc::import
+ $plugin load $format
+ set myplugin($format) $plugin
+ } else {
+ set plugin $myplugin($format)
+ }
+
+ return $plugin
+ }
+
+ method PluginSetup {mgr ip} {
+ # Inject a pseudo package into the plugin interpreter the
+ # import plugins can use to check that they were loaded into a
+ # proper environment.
+ $ip eval {package provide doctools::toc::import::plugin 1}
+
+ # The import plugins may use msgcat, which requires access to
+ # tcl_platform during its initialization, and won't have it by
+ # default. We trust them enough to hand out the information.
+ # TODO :: remove user/wordSize, etc. We need only 'os'.
+ $ip eval [list array set ::tcl_platform [array get ::tcl_platform]]
+
+ # Provide an alias-command a plugin can use to ask for any
+ # file, so that it can handle the processing of include files,
+ # should its format have that concept. Like doctoc. The alias
+ # will be directed to a method of ours and use the configured
+ # include paths to find the file, analogous to the GetFile
+ # procedure of doctools::toc::parse.
+
+ #8.5+: ::interp alias $ip include {} {*}[mymethod IncludeFile]
+ eval [linsert [mymethod IncludeFile] 0 ::interp alias $ip include {}]
+ return
+ }
+
+ method IncludeFile {currentfile path} {
+ # result = ok text fullpath error-code error-message
+
+ # Find the file, or not.
+ set fullpath [$self Locate $path]
+ if {$fullpath eq {}} {
+ return [list 0 {} $path notfound {}]
+ }
+
+ # Read contents, or not.
+ if {[catch {
+ set data [fileutil::cat $fullpath]
+ } msg]} {
+ set error notread
+ set emessage $msg
+ return [list 0 {} $fullpath notread $msg]
+ }
+
+ return [list 1 $data $fullpath {} {}]
+ }
+
+ method Locate {path} {
+ upvar 1 currentfile currentfile
+
+ if {$currentfile ne {}} {
+ set pathstosearch \
+ [linsert [$myinclude paths] 0 \
+ [file dirname [file normalize $currentfile]]]
+ } else {
+ set pathstosearch [$myinclude paths]
+ }
+
+ foreach base $pathstosearch {
+ set try [file join $base $path]
+ if {![file exists $try]} continue
+ return $try
+ }
+ # Nothing found
+ return {}
+ }
+
+ # ### ### ### ######### ######### #########
+ ## State
+
+ # Array serving as a cache for the various plugin managers holding
+ # a specific import plugin.
+
+ variable myplugin -array {}
+
+ # A component managing the configuration given to the import
+ # plugins when they are invoked.
+
+ component myconfig -public config
+ component myinclude -public include
+
+ ##
+ # ### ### ### ######### ######### #########
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::import 0.1
+return
diff --git a/tcllib/modules/doctools2toc/import.test b/tcllib/modules/doctools2toc/import.test
new file mode 100644
index 0000000..e8bf0e4
--- /dev/null
+++ b/tcllib/modules/doctools2toc/import.test
@@ -0,0 +1,377 @@
+# -*- tcl -*-
+# -- toc_import.test:
+# -- Tests for package "doctools::toc::import": Management of import plugins.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: import.test,v 1.1 2009/04/18 21:14:18 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2
+
+support {
+ use struct/list.tcl struct::list
+ use snit/snit.tcl snit
+ use fileutil/fileutil.tcl fileutil
+ use log/logger.tcl logger
+ use pluginmgr/pluginmgr.tcl pluginmgr
+
+ use doctools2base/config.tcl doctools::config
+ use doctools2base/paths.tcl doctools::paths
+
+ source [tcllibPath doctools2base/tests/common]
+}
+testing {
+ useLocalKeep import.tcl doctools::toc::import
+}
+
+# -------------------------------------------------------------------------
+
+setup_plugins
+
+# -------------------------------------------------------------------------
+
+test doctools-toc-import-1.0 {import text, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import text
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_text type selfns win self text ?format?"}
+
+test doctools-toc-import-1.1 {import text, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import text T F XX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_text type selfns win self text ?format?"}
+
+test doctools-toc-import-2.0 {import file, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import file
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_file type selfns win self path ?format?"}
+
+test doctools-toc-import-2.1 {import file, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import file P F XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_file type selfns win self path ?format?"}
+
+test doctools-toc-import-3.0 {import object text, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import object text
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_object_text type selfns win self obj text ?format?"}
+
+test doctools-toc-import-3.1 {import object text, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import object text O
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_object_text type selfns win self obj text ?format?"}
+
+test doctools-toc-import-3.2 {import object text, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import object text O T F XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_object_text type selfns win self obj text ?format?"}
+
+test doctools-toc-import-4.0 {import object file, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import object file
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_object_file type selfns win self obj path ?format?"}
+
+test doctools-toc-import-4.1 {import object file, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import object file O
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_object_file type selfns win self obj path ?format?"}
+
+test doctools-toc-import-4.2 {import object file, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I import object file O P F XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::import::Snit_hmethodimport_object_file type selfns win self obj path ?format?"}
+
+test doctools-toc-import-5.0 {config names, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I config names X
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::config::Snit_methodnames type selfns win self"}
+
+test doctools-toc-import-6.0 {config get, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I config get X
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::config::Snit_methodget type selfns win self"}
+
+test doctools-toc-import-7.0 {config set, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I config set
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::config::Snit_methodset type selfns win self name ?value?"}
+
+test doctools-toc-import-7.1 {config set, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I config set N V X
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::config::Snit_methodset type selfns win self name ?value?"}
+
+# config unset - accepts any number of arguments.
+
+test doctools-toc-import-8.0 {include paths, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I include paths X
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::paths::Snit_methodpaths type selfns win self"}
+
+test doctools-toc-import-9.0 {include clear, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I include clear X
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::paths::Snit_methodclear type selfns win self"}
+
+test doctools-toc-import-10.0 {include add, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I include add
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::paths::Snit_methodadd type selfns win self path"}
+
+test doctools-toc-import-10.1 {include add, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I include add P X
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::paths::Snit_methodadd type selfns win self path"}
+
+test doctools-toc-import-11.0 {include remove, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I include remove
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::paths::Snit_methodremove type selfns win self path"}
+
+test doctools-toc-import-11.1 {include remove, wrong#args} -setup {
+ doctools::toc::import I
+} -body {
+ I include remove P X
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::paths::Snit_methodremove type selfns win self path"}
+
+# -------------------------------------------------------------------------
+
+test doctools-toc-import-12.0 {config set, define single var} -setup {
+ doctools::toc::import I
+} -body {
+ I config set N V
+ I config get
+} -cleanup {
+ I destroy
+} -result {N V}
+
+test doctools-toc-import-12.1 {config set, define multiple vars} -setup {
+ doctools::toc::import I
+} -body {
+ I config set N V
+ I config set A B
+ dictsort [I config get]
+} -cleanup {
+ I destroy
+} -result {A B N V}
+
+test doctools-toc-import-12.2 {config set, as query} -setup {
+ doctools::toc::import I
+ I config set N V
+} -body {
+ I config set N
+} -cleanup {
+ I destroy
+} -result V
+
+test doctools-toc-import-13.0 {config unset, all} -setup {
+ doctools::toc::import I
+ I config set N V
+} -body {
+ I config unset
+ I config get
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-import-13.1 {config unset, by exact name} -setup {
+ doctools::toc::import I
+ I config set N V
+ I config set A B
+} -body {
+ I config unset N
+ I config get
+} -cleanup {
+ I destroy
+} -result {A B}
+
+test doctools-toc-import-13.2 {config unset, by glob pattern} -setup {
+ doctools::toc::import I
+ I config set N V
+ I config set N' V'
+ I config set A B
+} -body {
+ I config unset N*
+ I config get
+} -cleanup {
+ I destroy
+} -result {A B}
+
+test doctools-toc-import-14.0 {config names, empty} -setup {
+ doctools::toc::import I
+} -body {
+ I config names
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-import-14.1 {config names, with variables} -setup {
+ doctools::toc::import I
+ I config set N V
+ I config set A B
+} -body {
+ lsort -dict [I config names]
+} -cleanup {
+ I destroy
+} -result {A N}
+
+test doctools-toc-import-15.0 {config get, empty} -setup {
+ doctools::toc::import I
+} -body {
+ I config get
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-import-15.1 {config get, with variables} -setup {
+ doctools::toc::import I
+ I config set N V
+ I config set A B
+} -body {
+ dictsort [I config get]
+} -cleanup {
+ I destroy
+} -result {A B N V}
+
+test doctools-toc-import-16.0 {include paths, empty} -setup {
+ doctools::toc::import I
+} -body {
+ I include paths
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-import-16.1 {include paths, several paths, order} -setup {
+ doctools::toc::import I
+ I include add first
+ I include add second
+} -body {
+ I include paths
+} -cleanup {
+ I destroy
+} -result {first second}
+
+test doctools-toc-import-17.0 {include add, unknown} -setup {
+ doctools::toc::import I
+} -body {
+ I include add A
+ I include paths
+} -cleanup {
+ I destroy
+} -result A
+
+test doctools-toc-import-17.1 {include add, already known} -setup {
+ doctools::toc::import I
+} -body {
+ I include add A
+ I include add A
+ I include paths
+} -cleanup {
+ I destroy
+} -result A
+
+test doctools-toc-import-18.0 {include remove, unknown} -setup {
+ doctools::toc::import I
+} -body {
+ I include add A
+ I include remove B
+ I include paths
+} -cleanup {
+ I destroy
+} -result A
+
+test doctools-toc-import-18.1 {include remove, known} -setup {
+ doctools::toc::import I
+} -body {
+ I include add A
+ I include remove A
+ I include paths
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-import-19.0 {include clear} -setup {
+ doctools::toc::import I
+} -body {
+ I include add A
+ I include add B
+ I include clear
+ I include paths
+} -cleanup {
+ I destroy
+} -result {}
+
+# toc_import tests, numbering starts at 20
+# -------------------------------------------------------------------------
+
+source [localPath tests/import]
+
+#----------------------------------------------------------------------
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/import_doctoc.man b/tcllib/modules/doctools2toc/import_doctoc.man
new file mode 100644
index 0000000..5c42aef
--- /dev/null
+++ b/tcllib/modules/doctools2toc/import_doctoc.man
@@ -0,0 +1,6 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE doctoc]
+[vset NAME doctoc]
+[vset REQUIRE doctoc]
+[vset CONFIG doctoc]
+[include include/import/plugin.inc]
diff --git a/tcllib/modules/doctools2toc/import_doctoc.tcl b/tcllib/modules/doctools2toc/import_doctoc.tcl
new file mode 100644
index 0000000..eff659b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/import_doctoc.tcl
@@ -0,0 +1,91 @@
+# doctoc.tcl --
+#
+# The doctoc import plugin. Bridge between import management and
+# the parsing of doctoc markup.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: import_doctoc.tcl,v 1.3 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# This package is a plugin for the the doctools::toc v2 system. It
+# takes text in docidx format and produces the list serialization of a
+# table of contents.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: doctools::toc::import::plugin
+
+package require Tcl 8.4
+package require doctools::toc::import::plugin ; # The presence of this
+ # pseudo package
+ # indicates execution
+ # of this code inside
+ # of an interpreter
+ # which was properly
+ # initialized for use
+ # by import plugins.
+package require doctools::toc::parse ; # The actual doctoc
+ # parser used by the
+ # plugin.
+
+# ### ### ### ######### ######### #########
+
+## We redefine the command 'doctools::toc::parse::GetFile' to use the
+## 'include' alias provided by the plugin manager, as reguar file
+## commands are not allowed in this 'safe' environment. However this
+## is done if and only if we truly are in the plugin environment. The
+## testsuite, for example, will leave out the definition of 'include',
+## signaling in this way that the regular file operations can still be
+## used.
+
+if {[llength [info commands include]]} {
+
+ # Note: We are poking directly into the implementation of the
+ # class. Any changes to the interface here have to reviewed
+ # for their impact on doctools::toc::parse, and possibly
+ # ported over.
+
+ proc ::doctools::toc::parse::GetFile {currentfile path dv pv ev mv} {
+ upvar 1 $dv data $pv fullpath $ev error $mv emessage
+ foreach {ok data fullpath error emessage} [include $currentfile $path] break
+ return $ok
+ }
+}
+
+# ### ### ### ######### ######### #########
+## API :: Convert text to canonical toc serialization.
+
+proc import {text configuration} {
+ global errorInfo errorCode
+
+ doctools::toc::parse var load $configuration
+
+ # Could be done better using a try/finally
+ set code [catch {
+ doctools::toc::parse text $text
+ } serial]
+
+ # Save error state if there was any.
+ set ei $errorInfo
+ set ec $errorCode
+
+ # Cleanup parser configuration, regardless of errors or not.
+ doctools::toc::parse var unset *
+
+ # Rethrow any error, using the captured state.
+ if {$code} {
+ return -code $code -errorinfo $ei -errorcode $ec $serial
+ }
+
+ return $serial
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::import::doctoc 0.1
+return
diff --git a/tcllib/modules/doctools2toc/import_doctoc.test b/tcllib/modules/doctools2toc/import_doctoc.test
new file mode 100644
index 0000000..4067cac
--- /dev/null
+++ b/tcllib/modules/doctools2toc/import_doctoc.test
@@ -0,0 +1,92 @@
+# -*- tcl -*-
+# toc_import_doctoc.test: tests for the doctools::toc::import::doctoc package/plugin.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: import_doctoc.test,v 1.1 2009/04/18 21:14:18 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ useAccel [useTcllibC] struct/tree.tcl struct::tree
+ TestAccelInit struct::tree
+
+ useAccel [useTcllibC] struct/stack.tcl struct::stack
+ TestAccelInit struct::stack
+
+ useAccel [useTcllibC] struct/sets.tcl struct::set
+ TestAccelInit struct::set
+
+ use struct/list.tcl struct::list
+ use snit/snit.tcl snit
+ use fileutil/fileutil.tcl fileutil
+ use log/logger.tcl logger
+ use treeql/treeql.tcl treeql
+
+ use doctools2base/tcl_parse.tcl doctools::tcl::parse
+ use doctools2base/msgcat.tcl doctools::msgcat
+
+ useLocal msgcat_c.tcl doctools::msgcat::toc::c
+ useLocal structure.tcl doctools::toc::structure
+ useLocal parse.tcl doctools::toc::parse
+
+ msgcat::mclocale C
+}
+testing {
+ package provide doctools::toc::import::plugin 1
+ # The above fakes plugin environment. Well, not completely. By
+ # leaving out a definition for the 'include' alias the plugin is
+ # signaled that there is no need to overwrite the GetFile command
+ # of doctools::toc::parse with a version calling out to the plugin
+ # manager, i.e. that it can still use the regular file operations.
+
+ useLocal import_doctoc.tcl doctools::toc::import::doctoc
+}
+
+# -------------------------------------------------------------------------
+
+# General set of error cases regarding the number of arguments.
+
+test doctools-toc-import-doctoc-1.0 {import, wrong#args} -body {
+ import
+} -returnCodes error -result {wrong # args: should be "import text configuration"}
+
+test doctools-toc-import-doctoc-1.1 {import, wrong#args} -body {
+ import T
+} -returnCodes error -result {wrong # args: should be "import text configuration"}
+
+test doctools-toc-import-doctoc-1.2 {import, wrong#args} -body {
+ import T C XXX
+} -returnCodes error -result {wrong # args: should be "import text configuration"}
+
+# toc_import_doctoc tests, numbering starts at 2
+# -------------------------------------------------------------------------
+
+array_unset env LANG*
+array_unset env LC_*
+set env(LANG) C ; # Usually default if nothing is set, OS X requires this.
+
+# -------------------------------------------------------------------------
+
+TestAccelDo struct::stack stkimpl {
+ TestAccelDo struct::set setimpl {
+ TestAccelDo struct::tree impl {
+ source [localPath tests/import_doctoc]
+ }
+ }
+}
+
+#----------------------------------------------------------------------
+TestAccelExit struct::tree
+TestAccelExit struct::set
+TestAccelExit struct::stack
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/import_json.tcl b/tcllib/modules/doctools2toc/import_json.tcl
new file mode 100644
index 0000000..2d101c8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/import_json.tcl
@@ -0,0 +1,77 @@
+# json.tcl --
+#
+# The json import plugin. Bridge between import management and
+# the parsing of json markup.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id: import_json.tcl,v 1.3 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# This package is a plugin for the the doctools::toc v2 system. It
+# takes text in json format and produces the list serialization of a
+# table of contents.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+# @mdgen NODEP: doctools::toc::import::plugin
+
+package require Tcl 8.4
+package require doctools::toc::import::plugin ; # The presence of this
+ # pseudo package
+ # indicates execution
+ # of this code inside
+ # of an interpreter
+ # which was properly
+ # initialized for use
+ # by import plugins.
+package require doctools::toc::structure ; # Verification of the json
+ # parse result as a
+ # proper toc
+ # serialization.
+
+if {[package vcompare [package present Tcl] 8.5] < 0} {
+ if {[catch {
+ package require dict
+ }]} {
+ # Create a pure Tcl implementation of the dict methods
+ # required by json, and fake the presence of the dict package.
+ proc dict {cmd args} { return [uplevel 1 [linsert $args 0 dict/$cmd]] }
+ proc dict/create {} { return {} }
+ proc dict/set {var key val} {
+ upvar 1 $var a
+ array set x $a
+ set x($key) $val
+ set a [array get x]
+ return
+ }
+ package provide dict 1
+ }
+}
+
+package require json ; # The actual json parser used by the plugin.
+# Requires 8.5, or 8.4+dict.
+
+# ### ### ### ######### ######### #########
+
+# ### ### ### ######### ######### #########
+## API :: Convert text to canonical toc serialization.
+
+proc import {text configuration} {
+ # Note: We cannot fail here on duplicate keys in the input,
+ # especially for keywords and references, as we do for Tcl-based
+ # canonical toc serializations, because our underlying JSON parser
+ # automatically merges them, by taking only the last found
+ # definition. I.e. of two or more definitions for a key X the last
+ # overwrites all previous occurences.
+ return [doctools::toc::structure canonicalize [json::json2dict $text]]
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide doctools::toc::import::json 0.1
+return
diff --git a/tcllib/modules/doctools2toc/import_json.test b/tcllib/modules/doctools2toc/import_json.test
new file mode 100644
index 0000000..3bf27f9
--- /dev/null
+++ b/tcllib/modules/doctools2toc/import_json.test
@@ -0,0 +1,115 @@
+# -*- tcl -*-
+# toc_import_json.test: tests for the doctools::toc::import::json package/plugin.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: import_json.test,v 1.1 2009/04/18 21:14:19 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ use fileutil/fileutil.tcl fileutil
+ use struct/list.tcl struct::list
+
+ # Copy of code from import_json.tcl, to define dict support
+ # even where dict is not really present on the system.
+
+ if {[package vcompare [package present Tcl] 8.5] < 0} {
+ if {[catch {
+ package require dict
+ }]} {
+ # Create a pure Tcl implementation of the dict methods
+ # required by json, and fake the presence of the dict package.
+ proc dict {cmd args} { return [uplevel 1 [linsert $args 0 dict/$cmd]] }
+ proc dict/create {} { return {} }
+ proc dict/set {var key val} {
+ upvar 1 $var a
+ array set x $a
+ set x($key) $val
+ set a [array get x]
+ return
+ }
+ package provide dict 1
+ }
+ }
+ use json/json.tcl json
+
+ useLocal structure.tcl doctools::toc::structure
+
+ #msgcat::mclocale C
+}
+testing {
+ package provide doctools::toc::import::plugin 1
+ # The above fakes plugin environment. Well, not completely. By
+ # leaving out a definition for the 'include' alias the plugin is
+ # signaled that there is no need to overwrite the GetFile command
+ # of doctools::toc::parse with a version calling out to the plugin
+ # manager, i.e. that it can still use the regular file operations.
+
+ useLocal import_json.tcl doctools::toc::import::json
+}
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+
+# General set of error cases regarding the number of arguments.
+
+test doctools-toc-import-json-1.0 {import, wrong#args} -body {
+ import
+} -returnCodes error -result {wrong # args: should be "import text configuration"}
+
+test doctools-toc-import-json-1.1 {import, wrong#args} -body {
+ import T
+} -returnCodes error -result {wrong # args: should be "import text configuration"}
+
+test doctools-toc-import-json-1.2 {import, wrong#args} -body {
+ import T C XXX
+} -returnCodes error -result {wrong # args: should be "import text configuration"}
+
+# toc_import_json tests, numbering starts at 2
+# -------------------------------------------------------------------------
+
+# We are checking that the various forms of json markup, as can be
+# generated by doctools::toc(::export(::json)) are valid input to the
+# json parser.
+#
+# section {} holds the non-canonical input we have to accept and make
+# canonical to higher layers.
+
+foreach {k section} {
+ 0 {}
+ 1 -ultracompact
+ 2 -indented
+ 3 -indalign
+} {
+ TestFilesProcess $mytestdir ok json$section serial-print -> n label input data expected {
+ test doctools-toc-import-json-2.$k.$n "doctools::toc::import::json, $label$section, ok" -body {
+ doctools::toc::structure print [import $data {}]
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+
+# We test the error messages and codes thrown by the parser for a
+# variety of failure possibilities.
+
+TestFilesProcess $mytestdir fail json json-emsg -> n label input data expected {
+ test doctools-toc-import-json-3.$n "doctools::toc::import::json, $label, error message" -body {
+ import $data {}
+ } -returnCodes error -result $expected
+}
+
+#----------------------------------------------------------------------
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/include/concept.inc b/tcllib/modules/doctools2toc/include/concept.inc
new file mode 100644
index 0000000..a3f8b5c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/concept.inc
@@ -0,0 +1,47 @@
+[comment {
+ Description of the concepts used in tables of contents and how
+ their relate to each other. This is useful to understand the
+ serialization chosen for tables of contents.
+}]
+[list_begin enumerated]
+[enum]
+
+A [term {table of contents}] consists of a (possibly empty) list of
+[term elements].
+
+[enum]
+Each element in the list is identified by its label.
+
+[enum]
+Each element is either a [term reference], or a [term division].
+
+[enum]
+Each reference has an associated document, identified by a symbolic
+id, and a textual description.
+
+[enum]
+Each division may have an associated document, identified by a
+symbolic id.
+
+[enum]
+Each division consists consists of a (possibly empty) list of
+[term elements], with each element following the rules as specified in
+item 2 and above.
+
+[list_end]
+
+A few notes
+
+[list_begin enumerated]
+[enum]
+The above rules span up a tree of elements, with references as the
+leaf nodes, and divisions as the inner nodes, and each element
+representing an entry in the whole table of contents.
+
+[enum]
+The identifying labels of any element E are unique within their
+division (or toc), and the full label of any element E is the list of
+labels for all nodes on the unique path from the root of the tree to
+E, including E.
+
+[list_end]
diff --git a/tcllib/modules/doctools2toc/include/dependencies.inc b/tcllib/modules/doctools2toc/include/dependencies.inc
new file mode 100644
index 0000000..b64d1f1
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/dependencies.inc
@@ -0,0 +1,44 @@
+[comment {
+ ASCII diagram of the dependencies between the doctools v2 toc packages
+ ======================================================================
+}][example {
+ ~~~~~~~~~~~ doctools::toc ~~~~~~~~~~~
+ ~~ | ~~
+ doctools::toc::export ~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~ doctools::toc::import
+ | | |
+ +---------------+-------------------------+ | +------------------+---------------+-----------------------+---------------+
+ | | | | | | | | |
+doctools::config = | | | = doctools::include doctools::config doctools::paths
+ | | | | |
+ doctools::toc::export::<*> | | | doctools::toc::import::<*>
+ doctoc | | | doctoc, json
+ json | | | | \\
+ html | | | doctools::toc::parse \\
+ nroff | | | | \\
+ wiki | | | +---------------+ json
+ text | | | | |
+ doctools::toc::structure |
+ |
+ +-------+---------------+
+ | |
+ doctools::html doctools::html::cssdefaults doctools::tcl::parse doctools::msgcat
+ | |
+ doctools::text doctools::nroff::man_macros =
+ |
+ doctools::msgcat::toc::<*>
+ c, en, de, fr
+ (fr == en for now)
+ ~~ Interoperable objects, without actual package dependencies
+ -- Package dependency, higher requires lower package
+ = Dynamic dependency through plugin system
+ <*> Multiple packages following the given form of naming.
+
+}][comment {
+ yaml export, import
+ tmml export, import
+ reStructured Text export
+ latex export
+
+ list, desc - old, not needed under new system, replaced by the nested-list serialization
+ null - old, not needed, deserialize doctoc alone provides validation of input.
+}]
diff --git a/tcllib/modules/doctools2toc/include/export/config/doctoc.inc b/tcllib/modules/doctools2toc/include/export/config/doctoc.inc
new file mode 100644
index 0000000..199b892
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/config/doctoc.inc
@@ -0,0 +1,70 @@
+
+[include ../../format/doctoc.inc]
+
+[section Configuration]
+
+The doctoc export plugin recognizes the following configuration
+variables and changes its behaviour as they specify.
+
+[list_begin arguments]
+
+[arg_def string user]
+This standard configuration variable contains the name of the user
+running the process which invoked the export plugin.
+
+The plugin puts this information into the provenance comment at the
+beginning of the generated document.
+
+[arg_def string file]
+
+This standard configuration variable contains the name of the file the
+table of contents came from. This variable may not be set or contain
+the empty string.
+
+The plugin puts this information, if defined, i.e. set and not the
+empty string, into the provenance comment at the beginning of the
+generated document.
+
+
+[arg_def boolean newlines]
+
+If this flag is set the plugin will break the generated doctoc code
+across lines, with each markup command on a separate line.
+
+[para]
+
+If this flag is not set (the default), the whole document will be
+written on a single line, with minimum spacing between all elements.
+
+
+[arg_def boolean indented]
+
+If this flag is set the plugin will indent the markup commands
+according to the structure of tables of contents. To make this work
+this also implies that [var newlines] is set. This effect is
+independent of the value for [var aligned] however.
+
+[para]
+
+If this flag is not set (the default), the output is formatted as per
+the value of [var newlines], and no indenting is done.
+
+
+[arg_def boolean aligned]
+
+If this flag is set the generator ensures that the arguments for the
+[cmd item] commands in a division are aligned vertically for a nice
+table effect. To make this work this also implies that [var newlines]
+is set. This effect is independent of the value for [var indented]
+however.
+
+[para]
+
+If this flag is not set (the default), the output is formatted as per
+the values of [var newlines] and [var indented], and no alignment is
+done.
+
+[list_end]
+
+[emph Note] that this plugin ignores the standard configuration
+variables [var format], and [var map], and their values.
diff --git a/tcllib/modules/doctools2toc/include/export/config/html.inc b/tcllib/modules/doctools2toc/include/export/config/html.inc
new file mode 100644
index 0000000..faf0b86
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/config/html.inc
@@ -0,0 +1,155 @@
+[section Configuration]
+
+The html export plugin recognizes the following configuration
+variables and changes its behaviour as they specify.
+
+[list_begin arguments]
+
+[arg_def string user]
+This standard configuration variable contains the name of the user
+running the process which invoked the export plugin.
+
+The plugin puts this information into the provenance comment at the
+beginning of the generated document.
+
+[arg_def string file]
+
+This standard configuration variable contains the name of the file the
+table of contents came from. This variable may not be set or contain
+the empty string.
+
+The plugin puts this information, if defined, i.e. set and not the
+empty string, into the provenance comment at the beginning of the
+generated document.
+
+
+[arg_def dictionary map]
+
+This standard configuration variable contains a dictionary mapping
+from the (symbolic) document ids in reference entries to the actual
+filenames and/or urls to be used in the output.
+
+[para]
+
+Document ids without a mapping are used unchanged.
+
+
+[arg_def boolean newlines]
+
+If this flag is set the plugin will break the generated html code
+across lines, with each markup command on a separate line.
+
+[para]
+
+If this flag is not set (the default), the whole document will be
+written on a single line, with minimum spacing between all elements.
+
+
+[arg_def boolean indented]
+
+If this flag is set the plugin will indent the markup commands
+according to the structure of indices. To make this work this also
+implies that [var newlines] is set.
+
+[para]
+
+If this flag is not set (the default), the output is formatted as per
+the value of [var newlines], and no indenting is done.
+
+
+[arg_def string meta]
+
+This variable is meant to hold a fragment of HTML (default: empty).
+The fragment it contains will be inserted into the generated output in
+the <head> section of the document, just after the <title> tag.
+
+
+[arg_def string header]
+
+This variable is meant to hold a fragment of HTML (default: empty).
+The fragment it contains will be inserted into the generated output
+just after the <h1> title tag in the body of the document, in the
+class.header <div>'ision.
+
+
+
+[arg_def string footer]
+
+This variable is meant to hold a fragment of HTML (default:
+empty). The fragment it contains will be inserted into the generated
+output just before the </body> tag, in the class.footer <div>'ision.
+
+
+[arg_def dictionary rid]
+
+The value of this variable (default: empty) maps references to the
+identifiers to use as their anchor names. Each reference [var FOO] not
+found in the dictionary uses [const REF-][var FOO] as anchor,
+i.e. itself prefixed with the string [const REF-].
+
+
+[arg_def string sepline]
+
+The value of this variable is the string to use for the separator
+comments inserted into the output when the outpout is broken across
+lines and/or indented. The default string consists of 60 dashes.
+
+
+[arg_def string class.main]
+
+This variable contains the class name for the main <div>'ivision of
+the generated document. The default is [const doctools].
+
+
+[arg_def string class.header]
+
+This variable contains the class name for the header <div>'ision of
+the generated document. The default is [const toc-header]. This
+division contains the document title, the user specified [var header],
+if any, and a visible separator line.
+
+
+[arg_def string class.title]
+
+This variable contains the class name for the <h1> tag enclosing the
+document title. The default is [const toc-title].
+
+
+[arg_def string class.navsep]
+
+This variable contains the class name for the <hr> separators in the
+header and footer sections of the generated document. The default is
+[const toc-navsep].
+
+
+[arg_def string class.contents]
+
+This variable contains the class name for the XXXXX holding the
+keywords and their references in the generated document. The default
+is [const toc-contents].
+
+
+[arg_def string class.ref]
+
+This variable contains the class name for the table elements which are
+references to other documents. The default is [const toc-ref].
+
+
+[arg_def string class.div]
+
+This variable contains the class name for the table elements which are
+divisions. The default is [const toc-div].
+
+
+[arg_def string class.footer]
+
+This variable contains the class name for the footer <div>'ision of
+the generated document. The default is [const toc-footer]. This
+division contains a browser-visible separator line and the user
+specified [var footer], if any.
+
+
+[list_end]
+
+[emph Note] that this plugin ignores the standard configuration
+variable [var format], and its value.
diff --git a/tcllib/modules/doctools2toc/include/export/config/json.inc b/tcllib/modules/doctools2toc/include/export/config/json.inc
new file mode 100644
index 0000000..24844b8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/config/json.inc
@@ -0,0 +1,39 @@
+
+[include ../../format/json.inc]
+
+[section Configuration]
+
+The JSON export plugin recognizes the following configuration
+variables and changes its behaviour as they specify.
+
+[list_begin arguments]
+[arg_def boolean indented]
+
+If this flag is set the plugin will break the generated JSON code
+across lines and indent it according to its inner structure, with each
+key of a dictionary on a separate line.
+
+[para]
+
+If this flag is not set (the default), the whole JSON object will be
+written on a single line, with minimum spacing between all elements.
+
+
+[arg_def boolean aligned]
+
+If this flag is set the generator ensures that the values for the keys
+in a dictionary are vertically aligned with each other, for a nice
+table effect. To make this work this also implies that [var indented]
+is set.
+
+[para]
+
+If this flag is not set (the default), the output is formatted as per
+the value of [var indented], without trying to align the values for
+dictionary keys.
+
+[list_end]
+
+[emph Note] that this plugin ignores the standard configuration
+variables [var user], [var format], [var file], and [var map] and
+their values.
diff --git a/tcllib/modules/doctools2toc/include/export/config/nroff.inc b/tcllib/modules/doctools2toc/include/export/config/nroff.inc
new file mode 100644
index 0000000..5158ca1
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/config/nroff.inc
@@ -0,0 +1,40 @@
+[section Configuration]
+
+The nroff export plugin recognizes the following configuration
+variables and changes its behaviour as they specify.
+
+[list_begin arguments]
+
+[arg_def string user]
+This standard configuration variable contains the name of the user
+running the process which invoked the export plugin.
+
+The plugin puts this information into the provenance comment at the
+beginning of the generated document.
+
+[arg_def string file]
+
+This standard configuration variable contains the name of the file the
+table of contents came from. This variable may not be set or contain
+the empty string.
+
+The plugin puts this information, if defined, i.e. set and not the
+empty string, into the provenance comment at the beginning of the
+generated document.
+
+
+[arg_def boolean inline]
+
+If this flag is set (default) the plugin will place the definitions of
+the man macro set directly into the output.
+
+[para]
+
+If this flag is not set, the plugin will place a reference to the
+definitions of the man macro set into the output, but not the macro
+definitions themselves.
+
+[list_end]
+
+[emph Note] that this plugin ignores the standard configuration
+variables [var format], and [var map], and their values.
diff --git a/tcllib/modules/doctools2toc/include/export/config/text.inc b/tcllib/modules/doctools2toc/include/export/config/text.inc
new file mode 100644
index 0000000..5fe2a67
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/config/text.inc
@@ -0,0 +1,21 @@
+[section Configuration]
+
+The text export plugin recognizes the following configuration
+variables and changes its behaviour as they specify.
+
+[list_begin arguments]
+
+[arg_def dictionary map]
+
+This standard configuration variable contains a dictionary mapping
+from the (symbolic) document ids in reference entries to the actual
+filenames and/or urls to be used in the output.
+
+[para]
+
+Document ids without a mapping are used unchanged.
+
+[list_end]
+
+[emph Note] that this plugin ignores the standard configuration
+variables [var user], [var file], and [var format], and their values.
diff --git a/tcllib/modules/doctools2toc/include/export/config/wiki.inc b/tcllib/modules/doctools2toc/include/export/config/wiki.inc
new file mode 100644
index 0000000..fe9ba4c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/config/wiki.inc
@@ -0,0 +1,32 @@
+[section {Wiki markup}]
+
+The basic syntax of the wiki markup generated by this plugin are
+described at [uri http://wiki.tcl.tk/14].
+
+[para]
+
+The plugin goes beyond the classic markup to generate proper headers
+and indenting.
+
+
+[section Configuration]
+
+The wiki export plugin recognizes the following configuration
+variables and changes its behaviour as they specify.
+
+[list_begin arguments]
+
+[arg_def dictionary map]
+
+This standard configuration variable contains a dictionary mapping
+from the (symbolic) document ids in reference entries to the actual
+filenames and/or urls to be used in the output.
+
+[para]
+
+Document ids without a mapping are used unchanged.
+
+[list_end]
+
+[emph Note] that this plugin ignores the standard configuration
+variables [var user], [var file] and [var format], and their values.
diff --git a/tcllib/modules/doctools2toc/include/export/format/html.inc b/tcllib/modules/doctools2toc/include/export/format/html.inc
new file mode 100644
index 0000000..c8803f4
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/format/html.inc
@@ -0,0 +1,3 @@
+[require doctools::text]
+[require doctools::html]
+[require doctools::html::cssdefaults]
diff --git a/tcllib/modules/doctools2toc/include/export/format/json.inc b/tcllib/modules/doctools2toc/include/export/format/json.inc
new file mode 100644
index 0000000..9ef73f0
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/format/json.inc
@@ -0,0 +1 @@
+[require textutil::adjust]
diff --git a/tcllib/modules/doctools2toc/include/export/format/nroff.inc b/tcllib/modules/doctools2toc/include/export/format/nroff.inc
new file mode 100644
index 0000000..7883881
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/format/nroff.inc
@@ -0,0 +1,2 @@
+[require doctools::text]
+[require doctools::nroff::man_macros]
diff --git a/tcllib/modules/doctools2toc/include/export/format/null.inc b/tcllib/modules/doctools2toc/include/export/format/null.inc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/format/null.inc
diff --git a/tcllib/modules/doctools2toc/include/export/format/text.inc b/tcllib/modules/doctools2toc/include/export/format/text.inc
new file mode 100644
index 0000000..be41da5
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/format/text.inc
@@ -0,0 +1 @@
+[require doctools::text]
diff --git a/tcllib/modules/doctools2toc/include/export/plugin.inc b/tcllib/modules/doctools2toc/include/export/plugin.inc
new file mode 100644
index 0000000..cab8dd2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/export/plugin.inc
@@ -0,0 +1,55 @@
+[comment {-*- tcl -*- --- !doctools ---}]
+[manpage_begin doctools::toc::export::[vset PACKAGE] n [vset VERSION]]
+[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Documentation tools}]
+[titledesc "[vset NAME] export plugin"]
+[category {Text formatter plugin}]
+[require Tcl 8.4]
+[require doctools::toc::export::[vset PACKAGE] [opt [vset VERSION]]]
+[include format/[vset REQUIRE].inc]
+[keywords doctools toc {table of contents} serialization export [vset NAME]]
+[description]
+
+This package implements the doctools table of contents export plugin
+for the generation of [vset NAME] markup.
+
+[para]
+
+This is an internal package of doctools, for use by the higher level
+management packages handling tables of contents, especially [package \
+doctools::toc::export], the export manager.
+
+[para]
+
+Using it from a regular interpreter is possible, however only with
+contortions, and is not recommended.
+
+The proper way to use this functionality is through the package
+[package doctools::toc::export] and the export manager objects it
+provides.
+
+
+[section API]
+
+The API provided by this package satisfies the specification of the
+doctoc export plugin API version 2.
+
+[list_begin definitions]
+
+[call [cmd export] [arg serial] [arg configuration]]
+
+This command takes the canonical serialization of a table of contents,
+as specified in section [sectref {ToC serialization format}], and
+contained in [arg serial], the [arg configuration], a dictionary, and
+generates [vset NAME] markup encoding the table.
+
+The created string is then returned as the result of the command.
+
+[list_end]
+
+[include config/[vset CONFIG].inc]
+[include ../serialization.inc]
+
+[vset CATEGORY doctools]
+[include ../../../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/doctools2toc/include/format/doctoc.inc b/tcllib/modules/doctools2toc/include/format/doctoc.inc
new file mode 100644
index 0000000..6a82a7b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/format/doctoc.inc
@@ -0,0 +1,22 @@
+
+[section {[doctoc] notation of tables of contents}]
+
+The doctoc format for tables of contents, also called the
+[term {doctoc markup language}], is too large to be covered in single
+section.
+
+The interested reader should start with the document
+
+[list_begin enum]
+[enum] [manpage {doctoc language introduction}]
+[list_end]
+
+and then proceed from there to the formal specifications, i.e. the
+documents
+
+[list_begin enum]
+[enum] [manpage {doctoc language syntax}] and
+[enum] [manpage {doctoc language command reference}].
+[list_end]
+
+to get a thorough understanding of the language.
diff --git a/tcllib/modules/doctools2toc/include/format/json.inc b/tcllib/modules/doctools2toc/include/format/json.inc
new file mode 100644
index 0000000..1943241
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/format/json.inc
@@ -0,0 +1,74 @@
+
+[section {JSON notation of tables of contents}]
+
+The JSON format used for tables of contents is a direct translation of
+the [sectref {ToC serialization format}], mapping Tcl dictionaries as
+JSON objects and Tcl lists as JSON arrays.
+
+For example, the Tcl serialization
+
+[example {
+doctools::toc {
+ items {
+ {reference {
+ desc {DocTools - Tables of Contents}
+ id introduction.man
+ label doctools::toc::introduction
+ }}
+ {division {
+ id processing.man
+ items {
+ {reference {
+ desc {doctoc serialization utilities}
+ id structure.man
+ label doctools::toc::structure
+ }}
+ {reference {
+ desc {Parsing text in doctoc format}
+ id parse.man
+ label doctools::toc::parse
+ }}
+ }
+ label Processing
+ }}
+ }
+ label {Table of Contents}
+ title TOC
+}
+}]
+
+is equivalent to the JSON string
+
+[example {
+{
+ "doctools::toc" : {
+ "items" : [{
+ "reference" : {
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man",
+ "label" : "doctools::toc::introduction"
+ }
+ },{
+ "division" : {
+ "id" : "processing.man",
+ "items" : [{
+ "reference" : {
+ "desc" : "doctoc serialization utilities",
+ "id" : "structure.man",
+ "label" : "doctools::toc::structure"
+ }
+ },{
+ "reference" : {
+ "desc" : "Parsing text in doctoc format",
+ "id" : "parse.man",
+ "label" : "doctools::toc::parse"
+ }
+ }],
+ "label" : "Processing"
+ }
+ }],
+ "label" : "Table of Contents",
+ "title" : "TOC"
+ }
+}
+}]
diff --git a/tcllib/modules/doctools2toc/include/import/config/doctoc.inc b/tcllib/modules/doctools2toc/include/import/config/doctoc.inc
new file mode 100644
index 0000000..8ff41b9
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/import/config/doctoc.inc
@@ -0,0 +1 @@
+[include ../../format/doctoc.inc]
diff --git a/tcllib/modules/doctools2toc/include/import/config/json.inc b/tcllib/modules/doctools2toc/include/import/config/json.inc
new file mode 100644
index 0000000..8d1e06e
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/import/config/json.inc
@@ -0,0 +1 @@
+[include ../../format/json.inc]
diff --git a/tcllib/modules/doctools2toc/include/import/format/doctoc.inc b/tcllib/modules/doctools2toc/include/import/format/doctoc.inc
new file mode 100644
index 0000000..753fa4e
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/import/format/doctoc.inc
@@ -0,0 +1,12 @@
+[require doctools::toc::parse]
+[require doctools::toc::structure]
+[require doctools::msgcat]
+[require doctools::tcl::parse]
+[require fileutil]
+[require logger]
+[require snit]
+[require struct::list]
+[require struct::set]
+[require struct::stack]
+[require struct::tree]
+[require treeql]
diff --git a/tcllib/modules/doctools2toc/include/import/format/json.inc b/tcllib/modules/doctools2toc/include/import/format/json.inc
new file mode 100644
index 0000000..a16a34d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/import/format/json.inc
@@ -0,0 +1,2 @@
+[require doctools::toc::structure]
+[require json] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/include/import/plugin.inc b/tcllib/modules/doctools2toc/include/import/plugin.inc
new file mode 100644
index 0000000..abff582
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/import/plugin.inc
@@ -0,0 +1,55 @@
+[comment {-*- tcl -*- --- !doctools ---}]
+[manpage_begin doctools::toc::import::[vset PACKAGE] n 0.1]
+[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Documentation tools}]
+[titledesc "[vset NAME] import plugin"]
+[category {Text formatter plugin}]
+[require Tcl 8.4]
+[require doctools::toc::import::[vset PACKAGE] [opt 0.1]]
+[include format/[vset REQUIRE].inc]
+[keywords doctools toc {table of contents} deserialization import [vset NAME]]
+[description]
+
+This package implements the doctools table of contents import plugin
+for the parsing of [vset NAME] markup.
+
+[para]
+
+This is an internal package of doctools, for use by the higher level
+management packages handling tables of contents, especially [package \
+doctools::toc::import], the import manager.
+
+[para]
+
+Using it from a regular interpreter is possible, however only with
+contortions, and is not recommended.
+
+The proper way to use this functionality is through the package
+[package doctools::toc::import] and the import manager objects it
+provides.
+
+
+[section API]
+
+The API provided by this package satisfies the specification of the
+doctoc import plugin API version 2.
+
+[list_begin definitions]
+
+[call [cmd import] [arg string] [arg configuration]]
+
+This command takes the [arg string] and parses it as [vset NAME]
+markup encoding a table of contents, in the context of the specified
+[arg configuration] (a dictionary). The result of the command is the
+canonical serialization of that table of contents, in the form
+specified in section [sectref {ToC serialization format}].
+
+[list_end]
+
+
+[include config/[vset CONFIG].inc]
+[include ../serialization.inc]
+
+[vset CATEGORY doctools]
+[include ../../../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/doctools2toc/include/msgcat.inc b/tcllib/modules/doctools2toc/include/msgcat.inc
new file mode 100644
index 0000000..5a32bd0
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/msgcat.inc
@@ -0,0 +1,46 @@
+[comment {-*- tcl -*- --- !doctools ---}]
+[manpage_begin doctools::msgcat::toc::[vset PACKAGE] n 0.1]
+[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Documentation tools}]
+[titledesc "Message catalog for the doctoc parser ([vset NAME])"]
+[category {Documentation tools}]
+[require Tcl 8.4]
+[require msgcat]
+[require doctools::msgcat::toc::[vset PACKAGE] [opt 0.1]]
+[keywords doctools doctoc {message catalog}]
+[keywords localization l10n internationalization i18n]
+[keywords {catalog package} {message package}]
+[keywords [vset NAME]]
+[description]
+
+The package [package doctools::msgcat::toc::[vset PACKAGE]] is a
+support module providing the [vset LONGNAME] language message catalog
+for the doctoc parser in the doctools system version 2. As such it is
+an internal package a regular user (developer) should not be in direct
+contact with.
+
+[para]
+
+If you are such please go the documentation of either
+[list_begin enumerated]
+[enum] [package doctools::doc],
+[enum] [package doctools::toc], or
+[enum] [package doctools::idx]
+[list_end]
+[para]
+
+Within the system architecture this package resides under the package
+[package doctools::msgcat] providing the general message catalog
+management within the system. [emph Note] that there is [emph no]
+explicit dependency between the manager and catalog packages. The
+catalog is a plugin which is selected and loaded dynamically.
+
+
+[section API]
+
+This package has no exported API.
+
+
+[vset CATEGORY doctools]
+[include ../../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/doctools2toc/include/serialization.inc b/tcllib/modules/doctools2toc/include/serialization.inc
new file mode 100644
index 0000000..e8fc05e
--- /dev/null
+++ b/tcllib/modules/doctools2toc/include/serialization.inc
@@ -0,0 +1,131 @@
+[section {ToC serialization format}]
+
+Here we specify the format used by the doctools v2 packages to
+serialize tables of contents as immutable values for transport,
+comparison, etc.
+
+[para]
+
+We distinguish between [term regular] and [term canonical]
+serializations.
+
+While a table of contents may have more than one regular serialization
+only exactly one of them will be [term canonical].
+
+[para]
+
+[list_begin definitions][comment {-- serializations --}]
+[def {regular serialization}]
+
+[list_begin enumerated][comment {-- regular points --}]
+[enum]
+The serialization of any table of contents is a nested Tcl dictionary.
+
+[enum]
+This dictionary holds a single key, [const doctools::toc], and its
+value. This value holds the contents of the table of contents.
+
+[enum]
+
+The contents of the table of contents are a Tcl dictionary holding the
+title of the table of contents, a label, and its elements. The
+relevant keys and their values are
+
+[list_begin definitions][comment {-- keywords --}]
+[def [const title]]
+The value is a string containing the title of the table of contents.
+
+[def [const label]]
+The value is a string containing a label for the table of contents.
+
+[def [const items]]
+The value is a Tcl list holding the elements of the table, in the
+order they are to be shown.
+
+[para]
+Each element is a Tcl list holding the type of the item, and its
+description, in this order. An alternative description would be that
+it is a Tcl dictionary holding a single key, the item type, mapped to
+the item description.
+
+[para]
+The two legal item types and their descriptions are
+
+[list_begin definitions][comment {-- item types --}]
+[def [const reference]]
+This item describes a single entry in the table of contents,
+referencing a single document.
+
+To this end its value is a Tcl dictionary containing an id for the
+referenced document, a label, and a longer textual description which
+can be associated with the entry.
+
+The relevant keys and their values are
+
+[list_begin definitions][comment {-- reference keywords --}]
+[def [const id]]
+The value is a string containing the id of the document associated
+with the entry.
+
+[def [const label]]
+The value is a string containing a label for this entry. This string
+also identifies the entry, and no two entries (references and
+divisions) in the containing list are allowed to have the same label.
+
+[def [const desc]]
+The value is a string containing a longer description for this entry.
+
+[list_end][comment {-- reference keywords --}]
+
+
+[def [const division]]
+This item describes a group of entries in the table of contents,
+inducing a hierarchy of entries.
+
+To this end its value is a Tcl dictionary containing a label for the
+group, an optional id to a document for the whole group, and the list
+of entries in the group.
+
+The relevant keys and their values are
+
+[list_begin definitions][comment {-- division keywords --}]
+[def [const id]]
+The value is a string containing the id of the document associated
+with the whole group. This key is optional.
+
+[def [const label]]
+The value is a string containing a label for the group. This string
+also identifies the entry, and no two entries (references and
+divisions) in the containing list are allowed to have the same label.
+
+[def [const items]]
+The value is a Tcl list holding the elements of the group, in the
+order they are to be shown.
+
+This list has the same structure as the value for the keyword
+[const items] used to describe the whole table of contents, see
+above. This closes the recusrive definition of the structure, with
+divisions holding the same type of elements as the whole table of
+contents, including other divisions.
+
+[list_end][comment {-- division keywords --}]
+[list_end][comment {-- item types --}]
+[list_end][comment {-- keywords --}]
+[list_end][comment {-- regular points --}]
+
+[def {canonical serialization}]
+
+The canonical serialization of a table of contents has the format as
+specified in the previous item, and then additionally satisfies the
+constraints below, which make it unique among all the possible
+serializations of this table of contents.
+
+[list_begin enumerated][comment {-- canonical points --}]
+[enum]
+
+The keys found in all the nested Tcl dictionaries are sorted in
+ascending dictionary order, as generated by Tcl's builtin command
+[cmd {lsort -increasing -dict}].
+
+[list_end][comment {-- canonical points --}]
+[list_end][comment {-- serializations --}]
diff --git a/tcllib/modules/doctools2toc/msgcat_c.tcl b/tcllib/modules/doctools2toc/msgcat_c.tcl
new file mode 100644
index 0000000..31a8e54
--- /dev/null
+++ b/tcllib/modules/doctools2toc/msgcat_c.tcl
@@ -0,0 +1,28 @@
+# -*- tcl -*-
+package require msgcat
+namespace import ::msgcat::*
+
+mcset c doctoc/char/syntax {Bad character in string}
+mcset c doctoc/cmd/illegal {Illegal command "%1$s", not a doctoc command} ; # Details: cmdname
+mcset c doctoc/cmd/nested {Illegal use of "%1$s" as argument of other command} ; # Details: cmdname
+mcset c doctoc/cmd/toomanyargs {Too many args for "%1$s", at most %2$d allowed} ; # Details: cmdname, max#args
+mcset c doctoc/cmd/wrongargs {Wrong#args for "%1$s", need at least %2$d} ; # Details: cmdname, min#args
+mcset c doctoc/eof/syntax {Bad <eof>}
+mcset c doctoc/include/path/notfound {Include file "%1$s" not found} ; # Details: file name
+mcset c doctoc/include/read-failed {Unable to read include file "%1$s", %2$s} ; # Details: file name and error msg
+mcset c doctoc/include/syntax {Errors in include file "%1$s"}
+mcset c doctoc/plaintext {Plain text beyond whitespace is not allowed}
+mcset c doctoc/vset/varname/unknown {Unknown variable "%1$s"} ; # Details: variable name
+
+mcset c doctoc/division_end/missing {Expected [division_end], not found}
+mcset c doctoc/division_end/syntax {Unexpected [division_end], not allowed here}
+mcset c doctoc/division_start/syntax {Expected [division_start], not found}
+mcset c doctoc/item/syntax {Unexpected [item], not allowed here}
+mcset c doctoc/toc_begin/missing {Expected [toc_begin], not found}
+mcset c doctoc/toc_begin/syntax {Unexpected [toc_begin], not allowed here}
+mcset c doctoc/toc_end/missing {Expected [toc_end], not found}
+mcset c doctoc/toc_end/syntax {Unexpected [toc_end], not allowed here}
+
+mcset c doctoc/redef {Bad reuse of label "%1$s"}
+
+package provide doctools::msgcat::toc::c 0.1
diff --git a/tcllib/modules/doctools2toc/msgcat_de.tcl b/tcllib/modules/doctools2toc/msgcat_de.tcl
new file mode 100644
index 0000000..23ef4a2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/msgcat_de.tcl
@@ -0,0 +1,28 @@
+# -*- tcl -*-
+package require msgcat
+namespace import ::msgcat::*
+
+mcset de doctoc/char/syntax {Unerwartetes Zeichen im String}
+mcset de doctoc/cmd/illegal {Illegaler Befehl "%1$s", ist kein doctoc Befehl} ; # Details: cmdname
+mcset de doctoc/cmd/nested {Illegale Nutzung von "%1$s" als Argument eines anderen Befehles} ; # Details: cmdname
+mcset de doctoc/cmd/toomanyargs {Zu viele Argumente fuer "%1$s", hoechstens %2$d moeglich} ; # Details: cmdname, max#args
+mcset de doctoc/cmd/wrongargs {Zu wenig Argumente fuer "%1$s", mindestens %2$d notwendig} ; # Details: cmdname, min#args
+mcset de doctoc/eof/syntax {Unerwartetes Ende der Datei}
+mcset de doctoc/include/path/notfound {Include-Datei "%1$s" nicht gefunden} ; # Details: file name
+mcset de doctoc/include/read-failed {Konnte Include-Datei "%1$s" nicht lesen: %2$s} ; # Details: file name and error msg
+mcset de doctoc/include/syntax {Fehler in der Include-Datei "%1$s"}
+mcset de doctoc/plaintext {Normaler Text ist (mit Ausnahme von reinem Leerraum) nicht erlaubt}
+mcset de doctoc/vset/varname/unknown {Unbekannte Variable "%1$s"} ; # Details: variable name
+
+mcset de doctoc/division_end/missing {Erwarteter Befehl [division_end] nicht vorhanden}
+mcset de doctoc/division_end/syntax {[division_end] ist hier nicht erlaubt}
+mcset de doctoc/division_start/syntax {Erwarteter Befehl [division_start] nicht vorhanden}
+mcset de doctoc/item/syntax {[item] ist hier nicht erlaubt}
+mcset de doctoc/toc_begin/missing {Erwarteter Befehl [toc_begin] nicht vorhanden}
+mcset de doctoc/toc_begin/syntax {[toc_begin] ist hier nicht erlaubt}
+mcset de doctoc/toc_end/missing {Erwarteter Befehl [toc_end] nicht vorhanden}
+mcset de doctoc/toc_end/syntax {[toc_end] ist hier nicht erlaubt}
+
+mcset de doctoc/redef {Fehlerhafte Wiederverwendung des Labels "%1$s"}
+
+package provide doctools::msgcat::toc::de 0.1
diff --git a/tcllib/modules/doctools2toc/msgcat_en.tcl b/tcllib/modules/doctools2toc/msgcat_en.tcl
new file mode 100644
index 0000000..f996281
--- /dev/null
+++ b/tcllib/modules/doctools2toc/msgcat_en.tcl
@@ -0,0 +1,28 @@
+# -*- tcl -*-
+package require msgcat
+namespace import ::msgcat::*
+
+mcset en doctoc/char/syntax {Bad character in string}
+mcset en doctoc/cmd/illegal {Illegal command "%1$s", not a doctoc command} ; # Details: cmdname
+mcset en doctoc/cmd/nested {Illegal use of "%1$s" as argument of other command} ; # Details: cmdname
+mcset en doctoc/cmd/toomanyargs {Too many args for "%1$s", at most %2$d allowed} ; # Details: cmdname, max#args
+mcset en doctoc/cmd/wrongargs {Wrong#args for "%1$s", need at least %2$d} ; # Details: cmdname, min#args
+mcset en doctoc/eof/syntax {Bad <eof>}
+mcset en doctoc/include/path/notfound {Include file "%1$s" not found} ; # Details: file name
+mcset en doctoc/include/read-failed {Unable to read include file "%1$s", %2$s} ; # Details: file name and error msg
+mcset en doctoc/include/syntax {Errors in include file "%1$s"}
+mcset en doctoc/plaintext {Plain text beyond whitespace is not allowed}
+mcset en doctoc/vset/varname/unknown {Unknown variable "%1$s"} ; # Details: variable name
+
+mcset en doctoc/division_end/missing {Expected [division_end], not found}
+mcset en doctoc/division_end/syntax {Unexpected [division_end], not allowed here}
+mcset en doctoc/division_start/syntax {Expected [division_start], not found}
+mcset en doctoc/item/syntax {Unexpected [item], not allowed here}
+mcset en doctoc/toc_begin/missing {Expected [toc_begin], not found}
+mcset en doctoc/toc_begin/syntax {Unexpected [toc_begin], not allowed here}
+mcset en doctoc/toc_end/missing {Expected [toc_end], not found}
+mcset en doctoc/toc_end/syntax {Unexpected [toc_end], not allowed here}
+
+mcset en doctoc/redef {Bad reuse of label "%1$s"}
+
+package provide doctools::msgcat::toc::en 0.1
diff --git a/tcllib/modules/doctools2toc/msgcat_fr.tcl b/tcllib/modules/doctools2toc/msgcat_fr.tcl
new file mode 100644
index 0000000..7317aae
--- /dev/null
+++ b/tcllib/modules/doctools2toc/msgcat_fr.tcl
@@ -0,0 +1,31 @@
+# -*- tcl -*-
+package require msgcat
+namespace import ::msgcat::*
+
+# The texts are in english because I have do not have enough knowledge
+# of french to make the translation.
+
+mcset fr doctoc/char/syntax {Bad character in string}
+mcset fr doctoc/cmd/illegal {Illegal command "%1$s", not a doctoc command} ; # Details: cmdname
+mcset fr doctoc/cmd/nested {Illegal use of "%1$s" as argument of other command} ; # Details: cmdname
+mcset fr doctoc/cmd/toomanyargs {Too many args for "%1$s", at most %2$d allowed} ; # Details: cmdname, max#args
+mcset fr doctoc/cmd/wrongargs {Wrong#args for "%1$s", need at least %2$d} ; # Details: cmdname, min#args
+mcset fr doctoc/eof/syntax {Bad <eof>}
+mcset fr doctoc/include/path/notfound {Include file "%1$s" not found} ; # Details: file name
+mcset fr doctoc/include/read-failed {Unable to read include file "%1$s", %2$s} ; # Details: file name and error msg
+mcset fr doctoc/include/syntax {Errors in include file "%1$s"}
+mcset fr doctoc/plaintext {Plain text beyond whitespace is not allowed}
+mcset fr doctoc/vset/varname/unknown {Unknown variable "%1$s"} ; # Details: variable name
+
+mcset fr doctoc/division_end/missing {Expected [division_end], not found}
+mcset fr doctoc/division_end/syntax {Unexpected [division_end], not allowed here}
+mcset fr doctoc/division_start/syntax {Expected [division_start], not found}
+mcset fr doctoc/item/syntax {Unexpected [item], not allowed here}
+mcset fr doctoc/toc_begin/missing {Expected [toc_begin], not found}
+mcset fr doctoc/toc_begin/syntax {Unexpected [toc_begin], not allowed here}
+mcset fr doctoc/toc_end/missing {Expected [toc_end], not found}
+mcset fr doctoc/toc_end/syntax {Unexpected [toc_end], not allowed here}
+
+mcset fr doctoc/redef {Bad reuse of label "%1$s"}
+
+package provide doctools::msgcat::toc::fr 0.1
diff --git a/tcllib/modules/doctools2toc/parse.tcl b/tcllib/modules/doctools2toc/parse.tcl
new file mode 100644
index 0000000..0bb5e69
--- /dev/null
+++ b/tcllib/modules/doctools2toc/parse.tcl
@@ -0,0 +1,1058 @@
+# -*- tcl -*-
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+
+# Parser for doctoc formatted input. The result is a struct::tree
+# repesenting the contents of the document in a structured form.
+
+# - root = table, attributes for title and label.
+# - children of the root = if any, elements of the table, references and divisions.
+# - children of divisions = if any, elements of the division, references and divisions.
+#
+# The order of the elements under root, and of the elements under
+# their division reflects the order of the information in the parsed
+# document.
+
+# Attributes in the nodes, except root provide location information,
+# i.e. refering from there in the input the information is coming from
+# (human-readable output: line/col for end of token, offset start/end
+# for range covered by token.
+
+# # ## ### ##### ######## ############# #####################
+## Requirements
+
+package require Tcl 8.4 ; # Required runtime.
+package require doctools::toc::structure ; # Parse Tcl script, like subst.
+package require doctools::msgcat ; # Error message L10N
+package require doctools::tcl::parse ; # Parse Tcl script, like subst.
+package require fileutil ; # Easy loading of files.
+package require logger ; # User feedback.
+package require snit ; # OO system.
+package require struct::list ; # Assign
+package require struct::tree ; # Internal syntax tree
+
+# # ## ### ##### ######## ############# #####################
+##
+
+logger::initNamespace ::doctools::toc::parse
+snit::type ::doctools::toc::parse {
+ # # ## ### ##### ######## #############
+ ## Public API
+
+ typemethod file {path} {
+ log::debug [list $type file]
+ return [$type text [fileutil::cat $path] $path]
+ }
+
+ typemethod text {text {path {}}} {
+ log::debug [list $type text]
+
+ set ourfile $path
+
+ array set vars [array get ourvars]
+ array set _file {}
+ ClearErrors
+
+ set t [struct::tree AST]
+
+ Process $t $text [$t rootname] vars _file
+ StopOnErrors
+
+ ReshapeTree $t
+ StopOnErrors
+
+ set serial [Serialize $t]
+ StopOnErrors
+
+ $t destroy
+ return $serial
+ }
+
+ # # ## ### ##### ######## #############
+ ## Manage symbol table (vset variables).
+
+ typemethod vars {} {
+ return [array get ourvars]
+ }
+
+ typemethod {var set} {name value} {
+ set ourvars($name) $value
+ return
+ }
+
+ typemethod {var load} {dict} {
+ array set ourvars $dict
+ return
+ }
+
+ typemethod {var unset} {args} {
+ if {![llength $args]} { lappend args * }
+ foreach pattern $args {
+ array unset ourvars $pattern
+ }
+ return
+ }
+
+ # # ## ### ##### ######## #############
+ ## Manage search paths for include files.
+
+ typemethod includes {} {
+ return $ourincpaths
+ }
+
+ typemethod {include set} {paths} {
+ set ourincpaths [lsort -uniq $paths]
+ return
+ }
+
+ typemethod {include add} {path} {
+ lappend ourincpaths $path
+ set ourincpaths [lsort -uniq $ourincpaths]
+ return
+ }
+
+ typemethod {include remove} {path} {
+ set pos [lsearch $ourincpaths $path]
+ if {$pos < 0} return
+ set ourincpaths [lreplace $ourincpaths $pos $pos]
+ return
+ }
+
+ typemethod {include clear} {} {
+ set ourincpaths {}
+ return
+ }
+
+ # # ## ### ##### ######## #############
+
+ proc Process {t text root vv fv} {
+ upvar 1 $vv vars $fv _file
+
+ DropChildren $t $root
+
+ # Phase 1. Generate the basic syntax tree
+
+ if {[catch {
+ doctools::tcl::parse text $t $text $root
+ } msg]} {
+ if {![string match {doctools::tcl::parse *} $::errorCode]} {
+ # Not a parse error, rethrow.
+ return \
+ -code error \
+ -errorcode $::errorCode \
+ -errorinfo $::errorInfo \
+ $msg
+ }
+
+ # Parse error, low-level syntax breakdown, extract the
+ # machine-info from the errorCode, and report internally.
+ # See the documentation of doctools::tcl::parse for the
+ # definition of the format.
+ struct::list assign $::errorCode _ msg pos line col
+ # msg in {eof, char}
+ ReportAt $_file($root) [list $pos $pos] $line $col doctoc/$msg/syntax {}
+ return 0
+ }
+
+ #doctools::parse::tcl::ShowTreeX $t {Raw Result}
+
+ # Phase 2. Check for errors.
+
+ CheckBasicConstraints $t $root _file
+ ResolveVarsAndIncludes $t $root vars _file
+ return 1
+ }
+
+ proc CheckBasicConstraints {t root fv} {
+ ::variable ourfile
+ upvar 1 $fv _file
+
+ # Bottom-up walk through the nodes starting at the current
+ # root.
+
+ $t walk $root -type dfs -order pre n {
+ # Ignore the root node itself. Except for one thing: The
+ # path information is remembered for the root as well.
+
+ set _file($n) $ourfile
+ #puts "_file($n) = $ourfile"
+ if {$n eq $root} continue
+
+ switch -exact [$t get $n type] {
+ Text {
+ # Texts at the top level are irrelevant and
+ # removed. They have to contain only whitespace as
+ # well.
+ if {[$t depth $n] == 1} {
+ if {[regexp {[^[:blank:]\n]} [$t get $n text]]} {
+ Error $t $n doctoc/plaintext
+ }
+ MarkDrop $n
+ }
+ }
+ Word {
+ # Word nodes we ignore. They are just argument
+ # aggregators. They will be gone later, when
+ # reduce arguments to their text form.
+ }
+ Command {
+ set cmdname [$t get $n text]
+ set parens [$t parent $n]
+
+ if {$parens eq $root} {
+ set parentt {}
+ } else {
+ set parentt [$t get $parens type]
+ }
+ set nested 0
+
+ if {($parentt eq "Command") || ($parentt eq "Word")} {
+ # Commands can be children/arguments of other
+ # commands only in very restricted
+ # circumstances => rb, lb, vset/1.
+ set nested 1
+ if {![Nestable $t $n $cmdname errcmdname] && [Legal $cmdname]} {
+ # Report only legal un-nestable commands.
+ # Illegal commands get their own report,
+ # see below.
+ MakeErrorMsg $t $n doctoc/cmd/nested $errcmdname
+ }
+ }
+
+ if {![Legal $cmdname]} {
+ # Deletion is safe because we are walking
+ # bottom up. If nested we drop only the
+ # children and replace this node with a fake.
+ if {$nested} {
+ MakeErrorMsg $t $n doctoc/cmd/illegal $cmdname
+ } else {
+ Error $t $n doctoc/cmd/illegal $cmdname
+ MarkDrop $n
+ }
+
+ continue
+ }
+
+ # Check arguments of the legal commands only.
+ ArgInfo $cmdname min max
+ set argc [llength [$t children $n]]
+
+ if {$argc < $min} {
+ MakeErrorMsg $t $n doctoc/cmd/wrongargs $cmdname $min
+ } elseif {$argc > $max} {
+ MakeErrorMsg $t $n doctoc/cmd/toomanyargs $cmdname $max
+ }
+
+ # Convert the quoting commands for bracket into
+ # equivalent text nodes, and remove comments.
+ if {$cmdname eq "lb"} {
+ MakeText $t $n "\["
+ } elseif {$cmdname eq "rb"} {
+ MakeText $t $n "\]"
+ } elseif {$cmdname eq "comment"} {
+ # Remove comments or replace with error node (nested).
+ if {$nested} {
+ MakeError $t $n
+ } else {
+ MarkDrop $n
+ }
+ }
+ }
+ }
+ }
+
+ # Kill the nodes marked for removal now that the walker is not
+ # accessing them any longer.
+ PerformDrop $t
+
+ #doctools::parse::tcl::ShowTreeX $t {Basic Constraints}
+ return
+ }
+
+ proc ResolveVarsAndIncludes {t root vv fv} {
+ upvar 1 $vv vars $fv _file
+
+ # Now resolve include and vset uses ... This has to be done at
+ # the same time, as each include may (re)define variables.
+
+ # Bottom-up walk. Children before parent, and from the left =>
+ # Nested vset uses are resolved in the proper order.
+
+ $t walk $root -type dfs -order post n {
+ # Ignore the root node itself.
+ if {$n eq $root} continue
+
+ set ntype [$t get $n type]
+
+ switch -exact -- $ntype {
+ Text - Error {
+ # Ignore these nodes.
+ }
+ Word {
+ # Children have to be fully converted to Text, or,
+ # in case of trouble, Error. Aggregate the
+ # information.
+ CollapseWord $t $n
+ }
+ Command {
+ set cmdname [$t get $n text]
+
+ switch -exact -- $cmdname {
+ vset {
+ set argv [$t children $n]
+ switch -exact -- [llength $argv] {
+ 1 {
+ VariableUse $t $n [lindex $argv 0]
+ }
+ 2 {
+ struct::list assign $argv var val
+ VariableDefine $t $n $var $val
+ }
+ }
+ # vset commands at the structural toplevel are
+ # irrelevant and removed.
+ if {[$t depth $n] == 1} {
+ MarkDrop $n
+ }
+ }
+ include {
+ # Pulls vars, _file from this scope
+ ProcessInclude $t $n [lindex [$t children $n] 0]
+ }
+ default {
+ # For all other commands move the argument
+ # information into an attribute. Errors in
+ # the argument cause the command to conert
+ # into an error.
+ CollapseArguments $t $n
+ }
+ }
+ }
+ }
+ }
+
+ # Kill the nodes marked for removal now that the walker is
+ # not accessing them any longer.
+ PerformDrop $t
+
+ #doctools::parse::tcl::ShowTreeX $t {Vars/Includes Resolved}
+ return
+ }
+
+ proc ReshapeTree {t} {
+ upvar 1 _file _file
+
+ # We are assuming that there are no illegal commands in the
+ # tree, and further that all of lb, rb, vset, comment, and
+ # include are gone as well, per the operation of the previous
+ # phases (-> CheckBasicConstraints, ResolveVarsAndIncludes).
+ # The only commands which can occur here are
+ #
+ # toc_begin, toc_end, division_start, division_end, item
+
+ # Grammar:
+ # TOC := toc_begin ITEMS toc_end
+ # ITEMS := { item | DIV }
+ # DIV := division_start ITEMS division_end
+
+ # Hand coded LL(1) parser with explicit stack and state
+ # machine.
+
+ set root [$t rootname]
+ set children [$t children $root]
+ lappend children $root
+
+ $t set $root text <EOF>
+ $t set $root range {0 0}
+ $t set $root line 1
+ $t set $root col 0
+
+ set st [struct::stack %AUTO%]
+ set at {}
+ set state TOC
+
+ foreach n $children {
+ #puts ____[$t get $n text]($n)
+
+ set cmdname [$t get $n text]
+ #puts <$n>|$cmdname|$state|
+
+ # We store the location of the last node in the root, for
+ # use when an unexpected eof triggers an error.
+ if {$n ne $root} {
+ $t set $root range [$t get $n range]
+ $t set $root line [$t get $n line]
+ $t set $root col [$t get $n col]
+ }
+
+ # LL(1) parser table. State/Nexttoken determine action and
+ # next state.
+ switch -exact -- [list $state $cmdname] {
+ {TOC toc_begin} {
+ # Pull arguments of the proper toc_begin up into
+ # the root. Drop the expected node.
+ $t set $root argv [$t get $n argv]
+ $t delete $n
+ #puts \t/drop/$n
+ # Starting series of toplevel items and divisions.
+ # Destination for movement is root, and we remember
+ # the state.
+ $st push $at
+ $st push $state
+ set at $root
+ #puts \t/p=$at
+ set state ITEMS
+ }
+ {ITEMS item} {
+ # Move item to proper parent. Nothing needed to be
+ # done for the toplevel items.
+ }
+ {ITEMS division_start} -
+ {DIV division_start} {
+ # Sub division begins, toplevel or deeper. Mark it
+ # as new movement destination, and remember the
+ # state. Also, do not forget to move it as well.
+ if {$at ne $root} {
+ $t move $at end $n
+ #puts \t/moveto/$at
+ }
+ $st push $at
+ $st push $state
+ set at $n
+ #puts \t/p=$at
+ set state DIV
+ }
+ {ITEMS toc_end} {
+ # End of the document reached, with proper closing
+ # of sub divisions and all. Drop the node, and go
+ # to end state
+ set state EOF
+ $t delete $n
+ #puts \t/drop/$n
+ }
+ {DIV item} {
+ # Move item to proper parent.
+ $t move $at end $n
+ #puts \t/moveto/$at
+ }
+ {DIV division_end} {
+ # Drop the node, pop the state and restore the
+ # previous state/destination.
+ $t delete $n
+ #puts \t/drop/$n
+ set state [$st pop]
+ set at [$st pop]
+ #puts \t/p=$at
+ }
+ {EOF <EOF>} {
+ # Good, really reached the end. Nothing to be
+ # done.
+ }
+ {TOC division_end} -
+ {TOC division_start} -
+ {TOC item} -
+ {TOC toc_end} {
+ Error $t $n doctoc/toc_begin/missing
+ $t delete $n
+ #puts \t/drop/$n
+ }
+ {EOF division_start} -
+ {ITEMS division_end} -
+ {EOF division_end} -
+ {EOF item} -
+ {ITEMS toc_begin} -
+ {EOF toc_begin} -
+ {DIV toc_begin} -
+ {EOF toc_end} -
+ {DIV toc_end} {
+ # TODO ?! Split this, and add message which command was expected.
+ # Unexpected and wrong. The node is dropped.
+ Error $t $n doctoc/$cmdname/syntax
+ $t delete $n
+ #puts \t/drop/$n
+ }
+ {TOC <EOF>} {
+ Error $t $n doctoc/toc_begin/missing
+ }
+ {ITEMS <EOF>} {
+ Error $t $n doctoc/toc_end/missing
+ }
+ {DIV <EOF>} {
+ Error $t $n doctoc/division_end/missing
+ }
+ }
+ }
+
+ $st destroy
+
+ $t unset $root text
+ $t unset $root range
+ $t unset $root line
+ $t unset $root col
+
+ #doctools::parse::tcl::ShowTreeX $t Shaped/Structure
+ return
+ }
+
+ proc Serialize {t} {
+ upvar 1 _file _file
+ # We assume here that the tree is already in the correct
+ # shape/structure, i.e. root, children for references and
+ # divisions, with divisions possibly having children and well.
+
+ # We now extract the basic information about the table from
+ # the tree, do some higher level checking on the elements and
+ # return the serialization of the table generated from the
+ # extracted data.
+
+ set error 0
+ set root [$t rootname]
+
+ # Root delivers toc label and title.
+ struct::list assign [$t get $root argv] label title
+
+ set prefix ....
+ set items [GetDivision $t $root error]
+
+ if {$error} return
+ # Caller will handle the errors.
+
+ ## ### ### ### ######### ######### #########
+ ## The part below is identical to the serialization backend of
+ ## command 'doctools::toc::structure merge'.
+
+ # Now construct the result, from the inside out, with proper
+ # sorting at all levels.
+
+ set serial [list doctools::toc \
+ [list \
+ items $items \
+ label $label \
+ title $title]]
+
+ # Caller verify, ensure contract
+ #::doctools::toc::structure verify-as-canonical $serial
+ return $serial
+ }
+
+ proc GetDivision {t root ev} {
+ upvar 1 $ev error _file _file
+ array set l {} ; # Label counters
+ set items {}
+
+ # Each element in the tree
+ foreach element [$t children $root] {
+ switch -exact -- [$t get $element text] {
+ item {
+ struct::list assign [$t get $element argv] file label desc
+ lappend items [list reference [list \
+ desc $desc \
+ id $file \
+ label $label]]
+ lappend l($label) .
+ }
+ division_start {
+ struct::list assign [$t get $element argv] label file
+ set subitems [GetDivision $t $element error]
+ if {$error} return
+ set res {}
+ if {$file ne {}} {
+ lappend res id $file
+ }
+ lappend res \
+ items $subitems \
+ label $label
+ lappend items [list division $res]
+ lappend l($label) .
+ }
+ }
+ if {[llength $l($label)] > 1} {
+ MakeErrorMsg $t $element doctoc/redef $label
+ set error 1
+ return
+ }
+ }
+ return $items
+ }
+
+ # # ## ### ##### ######## #############
+
+ proc CollapseArguments {t n} {
+ #puts __CA($n)
+
+ set ok 1
+ set argv {}
+ foreach ch [$t children $n] {
+ lappend argv [$t get $ch text]
+ if {[$t get $ch type] eq "Error"} {
+ set ok 0
+ break
+ }
+ }
+ if {$ok} {
+ $t set $n argv $argv
+ DropChildren $t $n
+ } else {
+ MakeError $t $n
+ }
+ return
+ }
+
+ proc CollapseWord {t n} {
+ #puts __CW($n)
+
+ set ok 1
+ set text {}
+ foreach ch [$t children $n] {
+ append text [$t get $ch text]
+ if {[$t get $ch type] eq "Error"} {
+ set ok 0
+ break
+ }
+ }
+ if {$ok} {
+ MakeText $t $n $text
+ } else {
+ MakeError $t $n
+ }
+ return
+ }
+
+ proc VariableUse {t n var} {
+ upvar 1 vars vars _file _file
+
+ # vset/1 - the command returns text information to the
+ # caller. Extract the argument data.
+
+ set vartype [$t get $var type]
+ set varname [$t get $var text]
+
+ # Remove the now superfluous argument nodes.
+ DropChildren $t $n
+
+ if {$vartype eq "Error"} {
+ # First we check if the command is in trouble because it
+ # has a bogus argument. If so we convert it into an error
+ # node to signal even higher commands, and ignore it. We
+ # do not report an error, as the actual problem was
+ # reported already.
+
+ MakeError $t $n
+ } elseif {![info exists vars($varname)]} {
+ # Secondly we check if the referenced variable is
+ # known. If not it is trouble, and we report it.
+
+ MakeErrorMsg $t $n doctoc/vset/varname/unknown $varname
+ } elseif {[$t depth $n] == 1} {
+ # Commands at the structural toplevel are irrelevant and
+ # removed (see caller). They have to checked again however
+ # to see if the use introduced non-whitespace where it
+ # should not be.
+
+ if {[regexp {[^[:blank:]\n]} $vars($varname)]} {
+ Error $t $n doctoc/plaintext
+ }
+ } else {
+ MakeText $t $n $vars($varname)
+ }
+ }
+
+ proc VariableDefine {t n var val} {
+ upvar 1 vars vars
+
+ # vset/2 - the command links a variable to a value. Extract
+ # the argument data.
+
+ set vartype [$t get $var type]
+ set valtype [$t get $val type]
+ set varname [$t get $var text]
+ set value [$t get $val text]
+
+ # Remove the now superfluous argument nodes.
+ DropChildren $t $n
+
+ if {($vartype eq "Error") || ($valtype eq "Error")} {
+ # First we check if the command is in trouble because it
+ # has one or more bogus arguments. If so we convert it
+ # into an error node to signal even higher commands, and
+ # ignore it. We do not report an error, as the actual
+ # problem was reported already.
+
+ MakeError $t $n
+ return
+ }
+
+ # And save the change to the symbol table we are lugging
+ # around during the processing.
+
+ set vars($varname) $value
+ return
+ }
+
+ proc ProcessInclude {t n path} {
+ upvar 1 vars vars _file _file
+ ::variable ourfile
+
+ # include - the command returns file content and inserts it in
+ # the place of the command. First extract the argument data
+
+ set pathtype [$t get $path type]
+ set pathname [$t get $path text]
+
+ # Remove the now superfluous argument nodes.
+ DropChildren $t $n
+
+ # Check for problems stemming from other trouble.
+ if {$pathtype eq "Error"} {
+ # First we check if the command is in trouble because it
+ # has a bogus argument. If so convert it into an error
+ # node to signal even higher commands, and ignore it. We
+ # do not report an error, as the actual problem was
+ # reported already.
+
+ MakeError $t $n
+ return
+ }
+
+ if {![GetFile $ourfile $pathname text fullpath error emsg]} {
+ switch -exact -- $error {
+ notfound { Error $t $n doctoc/include/path/notfound $pathname }
+ notread { Error $t $n doctoc/include/read-failed $fullpath $emsg }
+ }
+ MarkDrop $n
+ return
+ }
+
+ # Parse the file. This also resolves variables further.
+
+ set currenterrors [GetErrors]
+ set currentpath $ourfile
+ ClearErrors
+
+ # WIBNI :: Remember the path as relative to the current path.
+ set ourfile $fullpath
+ if {![Process $t $text $n vars _file]} {
+
+ set newerrors [GetErrors]
+ SetErrors $currenterrors
+ set ourfile $currentpath
+ Error $t $n doctoc/include/syntax $fullpath $newerrors
+ MarkDrop $n
+ return
+ }
+
+ if {![$t numchildren $n]} {
+ # Inclusion did not generate additional content, we can
+ # ignore the command completely.
+ MarkDrop $n
+ return
+ }
+
+ # Create marker nodes which show the file entry/exit
+ # transitions. Disabled, makes shaping tree structure too
+ # complex. And checking the syntax as well, if we wish to have
+ # only proper complete structures in an include file. Need
+ # proper LR parser for that (is not LL(1)), or maybe even
+ # something like earley-aycock for full handling of an
+ # ambigous grammar.
+ if 0 {
+ set fstart [$t insert $n 0]
+ set fstop [$t insert $n end]
+
+ $t set $fstart type Command
+ $t set $fstop type Command
+
+ $t set $fstart text include_begin
+ $t set $fstop text include_end
+
+ $t set $fstart path $fullpath
+ $t set $fstop path $fullpath
+ }
+ # Remove the include command itself, merging its children
+ # into the place it occupied in its parent.
+ $t cut $n
+ return
+ }
+
+ # # ## ### ##### ######## #############
+
+ ## Note: The import plugin for doctoc rewrites the 'GetFile'
+ ## command below to make use of an alias provided by the
+ ## plugin manager. This re-enables the ability of this class
+ ## to handle include files which would otherwise be gone due
+ ## to the necessary file operations (exists, isfile,
+ ## readable, open, read) be disallowed by the safe
+ ## environment the plugin operates in.
+ ##
+ ## Any changes to GetFile have to reviewed for their impact on
+ ## doctools::toc::import::doctoc, and possibly ported over.
+
+ proc GetFile {currentfile path dv pv ev mv} {
+ upvar 1 $dv data $pv fullpath $ev error $mv emessage
+ set data {}
+ set error {}
+ set emessage {}
+
+ # Find the file, or not.
+ set fullpath [Locate $path]
+ if {$fullpath eq {}} {
+ set fullpath $path
+ set error notfound
+ return 0
+ }
+
+ # Read contents, or not.
+ if {[catch {
+ set data [fileutil::cat $fullpath]
+ } msg]} {
+ set error notread
+ set emessage $msg
+ return 0
+ }
+
+ return 1
+ }
+
+ proc Locate {path} {
+ upvar 1 currentfile currentfile
+
+ if {$currentfile ne {}} {
+ set pathstosearch \
+ [linsert $ourincpaths 0 \
+ [file dirname [file normalize $currentfile]]]
+ } else {
+ set pathstosearch $ourincpaths
+ }
+
+ foreach base $pathstosearch {
+ set try [file join $base $path]
+ if {![file exists $try]} continue
+ return $try
+ }
+ # Nothing found
+ return {}
+ }
+
+ # # ## ### ##### ######## #############
+ ## Management of nodes to kill
+
+ proc MarkDrop {n} {
+ ::variable ourtokill
+ lappend ourtokill $n
+ #puts %%mark4kill=$n|[info level -1]
+ return
+ }
+
+ proc DropChildren {t n} {
+ foreach child [$t children $n] {
+ MarkDrop $child
+ }
+ return
+ }
+
+ proc PerformDrop {t} {
+ ::variable ourtokill
+ #puts __PD($t)=<[join $ourtokill ,]>
+ foreach n $ourtokill {
+ #puts x($n/[$t exists $n])
+ if {![$t exists $n]} continue
+ #puts ^^DEL($n)
+ $t delete $n
+ }
+ set ourtokill {}
+ return
+ }
+
+ # # ## ### ##### ######## #############
+ ## Command predicates
+
+ proc Nestable {t n cmdname cv} {
+ upvar 1 $cv outname
+ set outname $cmdname
+ switch -exact -- $cmdname {
+ lb - rb { return 1 }
+ vset {
+ if {[$t numchildren $n] == 1} {
+ return 1
+ }
+ append outname /2
+ }
+ }
+ return 0
+ }
+
+ proc Legal {cmdname} {
+ ::variable ourcmds
+ #parray ourcmds
+ return [info exists ourcmds($cmdname)]
+ }
+
+ proc ArgInfo {cmdname minv maxv} {
+ ::variable ourcmds
+ upvar 1 $minv min $maxv max
+ foreach {min max} $ourcmds($cmdname) break
+ return
+ }
+
+ # # ## ### ##### ######## #############
+ ## Higher level error handling, node conversion.
+
+ proc MakeError {t n} {
+ #puts %%error=$n|[info level -1]
+ $t set $n type Error
+ DropChildren $t $n
+ return
+ }
+
+ proc MakeErrorMsg {t n msg args} {
+ upvar 1 _file _file
+ #puts %%error=$n|[info level -1]
+ Report $t $n $msg $args
+ $t set $n type Error
+ DropChildren $t $n
+ return
+ }
+
+ proc MakeText {t n text} {
+ #puts %%text=$n|[info level -1]
+ $t set $n type Text
+ $t set $n text $text
+ DropChildren $t $n
+ return
+ }
+
+ # # ## ### ##### ######## #############
+ ## Error reporting
+
+ proc Error {t n text args} {
+ upvar 1 _file _file
+ Report $t $n $text $args
+ }
+
+ proc Report {t n text details} {
+ upvar 1 _file _file
+ ReportAt $_file($n) [$t get $n range] [$t get $n line] [$t get $n col] $text $details
+ return
+ }
+
+ proc ReportAt {file range line col text details} {
+ ::variable ourerrors
+ #puts !![list $file $range $line $col $text $details]/[info level -1]
+ lappend ourerrors [list $file $range $line $col $text $details]
+ return
+ }
+
+ # # ## ### ##### ######## #############
+ ## Error Management
+
+ proc ClearErrors {} {
+ ::variable ourerrors {}
+ return
+ }
+
+ proc GetErrors {} {
+ ::variable ourerrors
+ return $ourerrors
+ }
+
+ proc SetErrors {t} {
+ ::variable ourerrors $t
+ return
+ }
+
+ # # ## ### ##### ######## #############
+ ## Error Response
+
+ proc StopOnErrors {} {
+ ::variable ourerrors
+ if {![llength $ourerrors]} return
+
+ upvar 1 t t
+ $t destroy
+
+ doctools::msgcat::init toc
+ set info [SortMessages $ourerrors]
+ set msg [Formatted $info {}]
+
+ return -code error -errorcode $info $msg
+ }
+
+ proc Formatted {errors prefix} {
+ set lines {}
+ foreach err $errors {
+ struct::list assign $err file range line col msg details
+ #8.5: set text [msgcat::mc $msg {*}$details]
+ set text [eval [linsert $details 0 msgcat::mc $msg]]
+ if {![string length $prefix] && [string length $file]} {
+ set prefix "\"$file\" "
+ }
+
+ lappend lines "${prefix}error on line $line.$col: $text"
+
+ if {$msg eq "doctoc/include/syntax"} {
+ struct::list assign $details path moreerrors
+ lappend lines [Formatted [SortMessages $moreerrors] "\"$path\": "]
+ }
+ }
+ return [join $lines \n]
+ }
+
+ proc SortMessages {messages} {
+ return [lsort -dict -index 0 \
+ [lsort -dict -index 2 \
+ [lsort -dict -index 3 \
+ [lsort -unique $messages]]]]
+ }
+
+ # # ## ### ##### ######## #############
+ ## Parser state
+
+ # Path to the file currently processed, if known. Empty if not known
+ typevariable ourfile {}
+
+ # Array of variables for use by vset. During parsing a local copy
+ # is used so that variables set by the document cannot spill back
+ # to the parser state.
+ typevariable ourvars -array {}
+
+ # List of paths to use when searching for an include file.
+ typevariable ourincpaths {}
+
+ # Record of errors found so far. List of 5-tuples containing token
+ # range, line, column of firt character after the token, error
+ # code, and error arguments, in this order.
+ typevariable ourerrors {}
+
+ # List of nodes marked for removal.
+ typevariable ourtokill {}
+
+ # Map of legal commands to their min/max number of arguments.
+ typevariable ourcmds -array {
+ comment {1 1}
+ include {1 1}
+ lb {0 0}
+ rb {0 0}
+ vset {1 2}
+
+ division_end {0 0}
+ division_start {1 2}
+ item {3 3}
+ toc_begin {2 2}
+ toc_end {0 0}
+ }
+
+ # # ## ### ##### ######## #############
+ ## Configuration
+
+ pragma -hasinstances no ; # singleton
+ pragma -hastypeinfo no ; # no introspection
+ pragma -hastypedestroy no ; # immortal
+
+ ##
+ # # ## ### ##### ######## #############
+}
+
+# # ## ### ##### ######## ############# #####################
+## Ready
+
+package provide doctools::toc::parse 0.1
+return
diff --git a/tcllib/modules/doctools2toc/parse.test b/tcllib/modules/doctools2toc/parse.test
new file mode 100644
index 0000000..2cf22f9
--- /dev/null
+++ b/tcllib/modules/doctools2toc/parse.test
@@ -0,0 +1,153 @@
+# -*- tcl -*-
+# doctoc_parse.test: tests for the doctools::toc::parse package.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: parse.test,v 1.1 2009/04/18 21:14:19 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ useAccel [useTcllibC] struct/tree.tcl struct::tree
+ TestAccelInit struct::tree
+
+ useAccel [useTcllibC] struct/stack.tcl struct::stack
+ TestAccelInit struct::stack
+
+ useAccel [useTcllibC] struct/sets.tcl struct::set
+ TestAccelInit struct::set
+
+ use struct/list.tcl struct::list
+ use snit/snit.tcl snit
+ use fileutil/fileutil.tcl fileutil
+ use log/logger.tcl logger
+ use treeql/treeql.tcl treeql
+
+ use doctools2base/tcl_parse.tcl doctools::tcl::parse
+ use doctools2base/msgcat.tcl doctools::msgcat
+ useLocal msgcat_c.tcl doctools::msgcat::toc::c
+ useLocal structure.tcl doctools::toc::structure
+
+ msgcat::mclocale C
+}
+testing {
+ useLocal parse.tcl doctools::toc::parse
+}
+
+# -------------------------------------------------------------------------
+
+# General set of error cases regarding the number of arguments.
+
+test doctools-toc-parse-1.0 {parse file, wrong#args} -body {
+ doctools::toc::parse file
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_typemethodfile type path"}
+
+test doctools-toc-parse-1.1 {parse file, wrong#args} -body {
+ doctools::toc::parse file P XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_typemethodfile type path"}
+
+test doctools-toc-parse-2.0 {parse text, wrong#args} -body {
+ doctools::toc::parse text
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_typemethodtext type text ?path?"}
+
+test doctools-toc-parse-2.1 {parse text, wrong#args} -body {
+ doctools::toc::parse text T P XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_typemethodtext type text ?path?"}
+
+test doctools-toc-parse-3.0 {vars, wrong#args} -body {
+ doctools::toc::parse vars XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_typemethodvars type"}
+
+test doctools-toc-parse-4.0 {var, bogus submethod} -body {
+ doctools::toc::parse var bogus
+} -returnCodes error -result {"::doctools::toc::parse var bogus" is not defined}
+
+test doctools-toc-parse-5.0 {var set, wrong#args} -body {
+ doctools::toc::parse var set
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodvar_set type name value"}
+
+test doctools-toc-parse-5.1 {var set, wrong#args} -body {
+ doctools::toc::parse var set N
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodvar_set type name value"}
+
+test doctools-toc-parse-5.2 {var set, wrong#args} -body {
+ doctools::toc::parse var set N V XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodvar_set type name value"}
+
+test doctools-toc-parse-6.0 {var load, wrong#args} -body {
+ doctools::toc::parse var load
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodvar_load type dict"}
+
+test doctools-toc-parse-6.1 {var load, wrong#args} -body {
+ doctools::toc::parse var load D XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodvar_load type dict"}
+
+# var unset - 0+ arguments, no checking possible.
+
+test doctools-toc-parse-7.0 {includes, wrong#args} -body {
+ doctools::toc::parse includes XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_typemethodincludes type"}
+
+test doctools-toc-parse-8.0 {include, bogus submethod} -body {
+ doctools::toc::parse include bogus
+} -returnCodes error -result {"::doctools::toc::parse include bogus" is not defined}
+
+test doctools-toc-parse-9.0 {include set, wrong#args} -body {
+ doctools::toc::parse include set
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodinclude_set type paths"}
+
+test doctools-toc-parse-9.1 {include set, wrong#args} -body {
+ doctools::toc::parse include set P XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodinclude_set type paths"}
+
+test doctools-toc-parse-10.0 {include add, wrong#args} -body {
+ doctools::toc::parse include add
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodinclude_add type path"}
+
+test doctools-toc-parse-10.1 {include add, wrong#args} -body {
+ doctools::toc::parse include add P XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodinclude_add type path"}
+
+test doctools-toc-parse-11.0 {include remove, wrong#args} -body {
+ doctools::toc::parse include remove
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodinclude_remove type path"}
+
+test doctools-toc-parse-11.1 {include remove, wrong#args} -body {
+ doctools::toc::parse include remove P XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodinclude_remove type path"}
+
+test doctools-toc-parse-12.0 {include clear, wrong#args} -body {
+ doctools::toc::parse include clear XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::parse::Snit_htypemethodinclude_clear type"}
+
+# toc_parse tests, numbering starts at 20
+# -------------------------------------------------------------------------
+
+array_unset env LANG*
+array_unset env LC_*
+set env(LANG) C ; # Usually default if nothing is set, OS X requires this.
+
+# -------------------------------------------------------------------------
+
+TestAccelDo struct::stack stkimpl {
+ TestAccelDo struct::set setimpl {
+ TestAccelDo struct::tree impl {
+ source [localPath tests/parse]
+ }
+ }
+}
+
+#----------------------------------------------------------------------
+TestAccelExit struct::tree
+TestAccelExit struct::set
+TestAccelExit struct::stack
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/pkgIndex.tcl b/tcllib/modules/doctools2toc/pkgIndex.tcl
new file mode 100644
index 0000000..03759e8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/pkgIndex.tcl
@@ -0,0 +1,33 @@
+if {![package vsatisfies [package provide Tcl] 8.4]} {return}
+
+# Packages for the doctools toc v2 implementation
+# (still v1.1 doctoc language).
+
+# - Index container, mutable toc objects
+# - Export and import management
+# - Export and import plugins
+# - Parser for doctoc markup, and handling serializations
+# - Message catalogs for the parser
+
+package ifneeded doctools::toc 2 [list source [file join $dir container.tcl]]
+
+package ifneeded doctools::toc::export 0.1 [list source [file join $dir export.tcl]]
+package ifneeded doctools::toc::import 0.1 [list source [file join $dir import.tcl]]
+
+package ifneeded doctools::toc::export::doctoc 0.1 [list source [file join $dir export_doctoc.tcl]]
+package ifneeded doctools::toc::export::html 0.1 [list source [file join $dir export_html.tcl]]
+package ifneeded doctools::toc::export::json 0.1 [list source [file join $dir export_json.tcl]]
+package ifneeded doctools::toc::export::nroff 0.2 [list source [file join $dir export_nroff.tcl]]
+package ifneeded doctools::toc::export::text 0.1 [list source [file join $dir export_text.tcl]]
+package ifneeded doctools::toc::export::wiki 0.1 [list source [file join $dir export_wiki.tcl]]
+
+package ifneeded doctools::toc::import::doctoc 0.1 [list source [file join $dir import_doctoc.tcl]]
+package ifneeded doctools::toc::import::json 0.1 [list source [file join $dir import_json.tcl]]
+
+package ifneeded doctools::toc::parse 0.1 [list source [file join $dir parse.tcl]]
+package ifneeded doctools::toc::structure 0.1 [list source [file join $dir structure.tcl]]
+
+package ifneeded doctools::msgcat::toc::c 0.1 [list source [file join $dir msgcat_c.tcl]]
+package ifneeded doctools::msgcat::toc::de 0.1 [list source [file join $dir msgcat_de.tcl]]
+package ifneeded doctools::msgcat::toc::en 0.1 [list source [file join $dir msgcat_en.tcl]]
+package ifneeded doctools::msgcat::toc::fr 0.1 [list source [file join $dir msgcat_fr.tcl]]
diff --git a/tcllib/modules/doctools2toc/structure.tcl b/tcllib/modules/doctools2toc/structure.tcl
new file mode 100644
index 0000000..edbaff6
--- /dev/null
+++ b/tcllib/modules/doctools2toc/structure.tcl
@@ -0,0 +1,388 @@
+# -*- tcl -*-
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
+
+# Verification of serialized tables of contents, and conversion
+# between serialized tables of contents and other data structures.
+
+# # ## ### ##### ######## ############# #####################
+## Requirements
+
+package require Tcl 8.4 ; # Required runtime.
+package require snit ; # OO system.
+
+# # ## ### ##### ######## ############# #####################
+##
+
+snit::type ::doctools::toc::structure {
+ # # ## ### ##### ######## #############
+ ## Public API
+
+ # Check that the proposed serialization of a table of contents is
+ # indeed such.
+
+ typemethod verify {serial {canonvar {}}} {
+ # Basic syntax: Length and outer type code
+ if {[llength $serial] != 2} {
+ return -code error $ourprefix$ourshort
+ }
+
+ foreach {tag contents} $serial break
+ #struct::list assign $serial tag contents
+
+ if {$tag ne $ourcode} {
+ return -code error $ourprefix[format $ourtag $tag]
+ }
+
+ if {[llength $contents] != 6} {
+ return -code error $ourprefix$ourcshort
+ }
+
+ # Unpack the contents, then check that all necessary keys are
+ # present. Together with the length check we can then also be
+ # sure that no other key is present either.
+ array set toc $contents
+
+ foreach k {label title items} {
+ if {[info exists toc($k)]} continue
+ return -code error $ourprefix[format $ourmiss $k]
+ }
+
+ if {$canonvar eq {}} {
+ VerifyDivision $toc(items)
+ } else {
+ upvar 1 $canonvar iscanonical
+
+ set iscanonical 1
+ VerifyDivision $toc(items) iscanonical
+
+ # Quick exit if the inner structure was already
+ # non-canonical.
+ if {!$iscanonical} return
+
+ # Now various checks if the keys and identifiers are
+ # properly sorted to make this a canonical serialization.
+
+ foreach {a _ b _ c _} $contents break
+ #struct::list assign $contents a _ b _ c _
+ if {[list $a $b $c] ne {items label title}} {
+ set iscanonical 0
+ }
+ }
+
+ # Everything checked out.
+ return
+ }
+
+ typemethod verify-as-canonical {serial} {
+ $type verify $serial iscanonical
+ if {!$iscanonical} {
+ return -code error $ourprefix$ourdupsort
+ }
+ return
+ }
+
+ typemethod canonicalize {serial} {
+ $type verify $serial iscanonical
+ if {$iscanonical} { return $serial }
+
+ # Unpack the serialization.
+ array set toc $serial
+ array set toc $toc(doctools::toc)
+ unset toc(doctools::toc)
+
+ # Construct result
+ set serial [list doctools::toc \
+ [list \
+ items [CanonicalizeDivision $toc(items)] \
+ label $toc(label) \
+ title $toc(title)]]
+ return $serial
+ }
+
+ # Merge the serialization of two indices into a new serialization.
+
+ typemethod merge {seriala serialb} {
+ $type verify $seriala
+ $type verify $serialb
+
+ # Merge using title and label of the second toc, and the new
+ # elements come after the existing.
+
+ # Unpack the definitions...
+ array set a $seriala ; array set a $a(doctools::toc) ; unset a(doctools::toc)
+ array set b $serialb ; array set a $b(doctools::toc) ; unset b(doctools::toc)
+
+ # Construct result
+ set serial [list doctools::toc \
+ [list \
+ items [MergeDivisions $a(items) $b(items)] \
+ label $b(label) \
+ title $b(title)]]
+
+ # Caller has to verify, ensure contract.
+ #$type verify-as-canonical $serial
+ return $serial
+ }
+
+ # Converts a toc serialization into a human readable string for
+ # test results. It assumes that the serialization is at least
+ # structurally sound.
+
+ typemethod print {serial} {
+ # Unpack the serialization.
+ array set toc $serial
+ array set toc $toc(doctools::toc)
+ unset toc(doctools::toc)
+ # Print
+ set lines {}
+ lappend lines [list doctools::toc $toc(label) $toc(title)]
+ PrintDivision lines $toc(items) .... ....
+ return [join $lines \n]
+ }
+
+ # # ## ### ##### ######## #############
+
+ proc VerifyDivision {items {canonvar {}}} {
+ if {$canonvar ne {}} {
+ upvar 1 $canonvar iscanonical
+ }
+
+ array set label {}
+
+ foreach element $items {
+ if {[llength $element] != 2} {
+ return -code error $ourprefix$oureshort
+ }
+ foreach {etype edata} $element break
+ #struct::list assign $element etype edata
+
+ switch -exact -- $etype {
+ reference {
+ # edata = dict (id, label, desc)
+ if {[llength $edata] != 6} {
+ return -code error $ourprefix$ourcshort
+ }
+ array set toc $edata
+ foreach k {id label desc} {
+ if {[info exists toc($k)]} continue
+ return -code error $ourprefix[format $ourmiss $k]
+ }
+ lappend label($toc(label)) .
+ if {$canonvar ne {}} {
+ foreach {a _ b _ c _} $edata break
+ #struct::list assign $edata a _ b _ c _
+ if {[list $a $b $c] ne {desc id label}} {
+ set iscanonical 0
+ }
+ }
+ }
+ division {
+ # edata = dict (id?, label, items)
+ if {([llength $edata] != 4) && ([llength $edata] != 6)} {
+ return -code error $ourprefix$ourdshort
+ }
+ array set toc $edata
+ foreach k {label items} {
+ if {[info exists toc($k)]} continue
+ return -code error $ourprefix[format $ourmiss $k]
+ }
+ lappend label($toc(label)) .
+ if {$canonvar eq {}} {
+ VerifyDivision $toc(items)
+ } else {
+ VerifyDivision $toc(items) iscanonical
+ if {$iscanonical} {
+ if {[info exists toc(id)]} {
+ foreach {a _ b _ c _} $edata break
+ #struct::list assign $edata a _ b _ c _
+ if {[list $a $b $c] ne {id items label}} {
+ set iscanonical 0
+ }
+ } else {
+ foreach {a _ b _} $edata break
+ #struct::list assign $edata a _ b _
+ if {[list $a $b] ne {items label}} {
+ set iscanonical 0
+ }
+ }
+ }
+ }
+ }
+ default {
+ return -code error $ourprefix[format $ouretag $etype]
+ }
+ }
+ unset toc
+ }
+
+ # Fail if labels are duplicated.
+ foreach k [array names label] {
+ if {[llength $label($k)] > 1} {
+ return -code error $ourprefix$ourldup
+ }
+ }
+
+ return
+ }
+
+ proc CanonicalizeDivision {items} {
+ set result {}
+ foreach element $items {
+ foreach {etype edata} $element break
+ #struct::list assign $element etype edata
+
+ array set toc $edata
+ switch -exact -- $etype {
+ reference {
+ set element \
+ [list \
+ desc $toc(desc) \
+ id $toc(id) \
+ label $toc(label)]
+ }
+ division {
+ set element {}
+ if {[info exists toc(id)]} {
+ lappend element id $toc(id)
+ }
+ lappend element \
+ items [CanonicalizeDivision $toc(items)] \
+ label $toc(label)
+ }
+ }
+ unset toc
+ lappend result [list $etype $element]
+ }
+ return $result
+ }
+
+ proc PrintDivision {lv items prefix increment} {
+ upvar 1 $lv lines
+
+ foreach element $items {
+ foreach {etype edata} $element break
+ #struct::list assign $element etype edata
+ array set toc $edata
+ switch -exact -- $etype {
+ reference {
+ lappend lines $prefix[list $toc(id) $toc(label) $toc(desc)]
+ }
+ division {
+ set buf {}
+ if {[info exists toc(id)]} {
+ lappend buf $toc(id)
+ }
+ lappend buf $toc(label)
+ lappend lines $prefix$buf
+ PrintDivision lines $toc(items) $prefix$increment $increment
+ }
+ }
+ unset toc
+ }
+ return
+ }
+
+ proc MergeDivisions {aitems bitems} {
+
+ # Unpack the b-items for easy access when looping over a.
+ array set b
+ foreach element $bitems {
+ foreach {etype edata} $element break
+ array set toc $edata
+ set b($toc(label)) [list $etype $edata]
+ unset toc
+ }
+
+ set items {}
+
+ # Unification loop...
+ foreach element $aitems {
+ foreach {etype edata} $element break
+ array set toc $edata
+ set label $toc(label)
+ if {![info exists b($label)]} {
+ # Nothing in b, keep entry as is.
+ lappend items $element
+ } else {
+ # Unify. Type dependent. And throw an if the types do
+ # not match.
+ foreach {btype bdata} $b($label) break
+ if {$etype ne $btype} {
+ # TODO :: More details in error message to show
+ # where the mismatch is.
+ return -code error "Merge error"
+ }
+ switch -exact -- $etype {
+ reference {
+ # Unification by taking the b-information.
+ lappend items $b($label)
+ }
+ division {
+ # Unification by taking the b-information
+ # where possible, and merging the sub-ordinate
+ # items.
+ array set btoc $bdata
+ set element {}
+ if {[info exists btoc(id)]} {
+ lappend element id $btoc(id)
+ } elseif {[info exists toc(id)]} {
+ lappend element id $toc(id)
+ }
+ lappend element \
+ items [MergeDivisions $toc(items) $btoc(items)] \
+ label $btoc(label)
+ unset btoc
+ lappend items [list $etype $element]
+ }
+ }
+ unset b($label)
+ }
+ unset toc
+ }
+
+ # Appending loop. Now we add everything from b which was not
+ # unified with data in a.
+ foreach element $bitems {
+ foreach {etype edata} $element break
+ array set toc $edata
+ set label $toc(label)
+ if {![info exists b($label)]} continue
+ lappend items $element
+ }
+
+ return $items
+ }
+
+ # # ## ### ##### ######## #############
+
+ typevariable ourcode doctools::toc
+ typevariable ourprefix {error in serialization:}
+ # # Test cases (doctools-toc-structure-)
+ typevariable ourshort { dictionary too short, expected exactly one key} ; # 6.0
+ typevariable ourtag { bad type tag "%s"} ; # 6.1
+ typevariable ourcshort { dictionary too short, expected exactly three keys} ; # 6.2, 6.9
+ typevariable ourdshort { dictionary too short, expected two or three keys} ; # 6.14
+ typevariable ourmiss { missing expected key "%s"} ; # 6.3, 6.4, 6.5, 6.10, 6.11, 6.12, 6.15, 6.16 (XXX + inner: div)
+ typevariable ourldup { duplicate labels} ; # 6.19, 6.20, 6.21
+ typevariable oureshort { element list wrong, need exactly 2} ; # 6.7
+ typevariable ouretag { bad element tag "%s"} ; # 6.8
+ # Message for non-canonical serialization when expecting canonical form
+ typevariable ourdupsort { duplicate and/or unsorted keywords} ; # 6.6, 6.13, 6.17, 6.18
+ typevariable ourmergeerr {Mismatching declarations '%s' vs. '%s' for '%s'}
+
+ # # ## ### ##### ######## #############
+ ## Configuration
+
+ pragma -hasinstances no ; # singleton
+ pragma -hastypeinfo no ; # no introspection
+ pragma -hastypedestroy no ; # immortal
+
+ ##
+ # # ## ### ##### ######## #############
+}
+
+# # ## ### ##### ######## ############# #####################
+## Ready
+
+package provide doctools::toc::structure 0.1
+return
diff --git a/tcllib/modules/doctools2toc/structure.test b/tcllib/modules/doctools2toc/structure.test
new file mode 100644
index 0000000..58dffb6
--- /dev/null
+++ b/tcllib/modules/doctools2toc/structure.test
@@ -0,0 +1,212 @@
+# -*- tcl -*-
+# doctoc_structure.test: tests for the doctools::toc::structure package.
+#
+# Copyright (c) 2009 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: structure.test,v 1.1 2009/04/18 21:14:19 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.4
+testsNeedTcltest 2.0
+
+support {
+ use fileutil/fileutil.tcl fileutil ; # For tests/common
+ use snit/snit.tcl snit
+}
+testing {
+ useLocal structure.tcl doctools::toc::structure
+}
+
+# -------------------------------------------------------------------------
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+
+test doctools-toc-structure-1.0 {structure verify, wrong#args} -body {
+ doctools::toc::structure verify
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::structure::Snit_typemethodverify type serial ?canonvar?"}
+
+test doctools-toc-structure-1.1 {structure verify, wrong#args} -body {
+ doctools::toc::structure verify S V XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::structure::Snit_typemethodverify type serial ?canonvar?"}
+
+test doctools-toc-structure-2.0 {structure verify, wrong#args} -body {
+ doctools::toc::structure verify-as-canonical
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::structure::Snit_typemethodverify-as-canonical type serial"}
+
+test doctools-toc-structure-2.1 {structure verify, wrong#args} -body {
+ doctools::toc::structure verify-as-canonical S XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::structure::Snit_typemethodverify-as-canonical type serial"}
+
+test doctools-toc-structure-3.0 {structure print, wrong#args} -body {
+ doctools::toc::structure print
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::structure::Snit_typemethodprint type serial"}
+
+test doctools-toc-structure-3.1 {structure print, wrong#args} -body {
+ doctools::toc::structure print S XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::structure::Snit_typemethodprint type serial"}
+
+test doctools-toc-structure-4.0 {structure merge, wrong#args} -body {
+ doctools::toc::structure merge
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::structure::Snit_typemethodmerge type seriala serialb"}
+
+test doctools-toc-structure-4.1 {structure merge, wrong#args} -body {
+ doctools::toc::structure merge SA
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::structure::Snit_typemethodmerge type seriala serialb"}
+
+test doctools-toc-structure-4.2 {structure merge, wrong#args} -body {
+ doctools::toc::structure merge SA SB XXX
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::structure::Snit_typemethodmerge type seriala serialb"}
+
+# -------------------------------------------------------------------------
+
+TestFilesProcess $mytestdir ok serial text -> n label input data expected {
+ # The 'expected' data is irrelevant here, only used to satisfy
+ # TestFilesProcess' syntax.
+ test doctools-toc-structure-5.$n "doctools::toc::structure verify, $label, ok" -body {
+ doctools::toc::structure verify $data
+ } -result {}
+}
+
+# -------------------------------------------------------------------------
+
+foreach {n badserial expected} {
+ 0 {}
+ {error in serialization: dictionary too short, expected exactly one key}
+ 1 {FOO {}}
+ {error in serialization: bad type tag "FOO"}
+ 2 {doctools::toc {}}
+ {error in serialization: dictionary too short, expected exactly three keys}
+ 3 {doctools::toc {a . b . c .}}
+ {error in serialization: missing expected key "label"}
+ 4 {doctools::toc {label . b . c .}}
+ {error in serialization: missing expected key "title"}
+ 5 {doctools::toc {label . title . c .}}
+ {error in serialization: missing expected key "items"}
+ 6 {doctools::toc {label . title . items {}}}
+ {error in serialization: duplicate and/or unsorted keywords}
+ 7 {doctools::toc {items {{}} label . title .}}
+ {error in serialization: element list wrong, need exactly 2}
+ 8 {doctools::toc {items {{FOO {}}} label . title .}}
+ {error in serialization: bad element tag "FOO"}
+ 9 {doctools::toc {items {{reference {}}} label . title .}}
+ {error in serialization: dictionary too short, expected exactly three keys}
+ 10 {doctools::toc {items {
+ {reference {a . b . c .}}} label . title .}}
+ {error in serialization: missing expected key "id"}
+ 11 {doctools::toc {items {
+ {reference {id . b . c .}}} label . title .}}
+ {error in serialization: missing expected key "label"}
+ 12 {doctools::toc {items {
+ {reference {id . label . c .}}} label . title .}}
+ {error in serialization: missing expected key "desc"}
+ 13 {doctools::toc {items {
+ {reference {id . label . desc .}}} label . title .}}
+ {error in serialization: duplicate and/or unsorted keywords}
+ 14 {doctools::toc {items {
+ {division {}}} label . title .}}
+ {error in serialization: dictionary too short, expected two or three keys}
+ 15 {doctools::toc {items {
+ {division {a . b .}}} label . title .}}
+ {error in serialization: missing expected key "label"}
+ 16 {doctools::toc {items {
+ {division {label . b .}}} label . title .}}
+ {error in serialization: missing expected key "items"}
+ 17 {doctools::toc {items {
+ {division {label . items {}}}} label . title .}}
+ {error in serialization: duplicate and/or unsorted keywords}
+ 18 {doctools::toc {items {
+ {division {items {} label . id .}}} label . title .}}
+ {error in serialization: duplicate and/or unsorted keywords}
+ 19 {doctools::toc {items {
+ {reference {desc . id . label .}}
+ {reference {desc . id . label .}}} label . title .}}
+ {error in serialization: duplicate labels}
+ 20 {doctools::toc {items {
+ {division {id . items {} label .}}
+ {division {id . items {} label .}}} label . title .}}
+ {error in serialization: duplicate labels}
+ 21 {doctools::toc {items {
+ {division {id . items {} label .}}
+ {reference {desc . id . label .}}} label . title .}}
+ {error in serialization: duplicate labels}
+} {
+ test doctools-toc-structure-6.$n "doctools::toc::structure verify-as-canonical, error" -body {
+ doctools::toc::structure verify-as-canonical $badserial
+ } -returnCodes error -result $expected
+}
+
+#----------------------------------------------------------------------
+
+foreach {n badserial expected} {
+ 0 {}
+ {error in serialization: dictionary too short, expected exactly one key}
+ 1 {FOO {}}
+ {error in serialization: bad type tag "FOO"}
+ 2 {doctools::toc {}}
+ {error in serialization: dictionary too short, expected exactly three keys}
+ 3 {doctools::toc {a . b . c .}}
+ {error in serialization: missing expected key "label"}
+ 4 {doctools::toc {label . b . c .}}
+ {error in serialization: missing expected key "title"}
+ 5 {doctools::toc {label . title . c .}}
+ {error in serialization: missing expected key "items"}
+ 7 {doctools::toc {items {{}} label . title .}}
+ {error in serialization: element list wrong, need exactly 2}
+ 8 {doctools::toc {items {{FOO {}}} label . title .}}
+ {error in serialization: bad element tag "FOO"}
+ 9 {doctools::toc {items {{reference {}}} label . title .}}
+ {error in serialization: dictionary too short, expected exactly three keys}
+ 10 {doctools::toc {items {
+ {reference {a . b . c .}}} label . title .}}
+ {error in serialization: missing expected key "id"}
+ 11 {doctools::toc {items {
+ {reference {id . b . c .}}} label . title .}}
+ {error in serialization: missing expected key "label"}
+ 12 {doctools::toc {items {
+ {reference {id . label . c .}}} label . title .}}
+ {error in serialization: missing expected key "desc"}
+ 14 {doctools::toc {items {
+ {division {}}} label . title .}}
+ {error in serialization: dictionary too short, expected two or three keys}
+ 15 {doctools::toc {items {
+ {division {a . b .}}} label . title .}}
+ {error in serialization: missing expected key "label"}
+ 16 {doctools::toc {items {
+ {division {label . b .}}} label . title .}}
+ {error in serialization: missing expected key "items"}
+ 19 {doctools::toc {items {
+ {reference {desc . id . label .}}
+ {reference {desc . id . label .}}} label . title .}}
+ {error in serialization: duplicate labels}
+ 20 {doctools::toc {items {
+ {division {id . items {} label .}}
+ {division {id . items {} label .}}} label . title .}}
+ {error in serialization: duplicate labels}
+ 21 {doctools::toc {items {
+ {division {id . items {} label .}}
+ {reference {desc . id . label .}}} label . title .}}
+ {error in serialization: duplicate labels}
+} {
+ test doctools-toc-structure-7.$n "doctools::toc::structure verify, error" -body {
+ doctools::toc::structure verify $badserial
+ } -returnCodes error -result $expected
+}
+
+#----------------------------------------------------------------------
+
+# TODO merge ... also test cases for doctools::toc
+
+#----------------------------------------------------------------------
+
+unset mytestdir n badserial expected label input data
+testsuiteCleanup
+return
diff --git a/tcllib/modules/doctools2toc/tests/container b/tcllib/modules/doctools2toc/tests/container
new file mode 100644
index 0000000..ef393d5
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/container
@@ -0,0 +1,379 @@
+# -*- tcl -*-
+# doctoc.testsuite: tests for the doctoc management.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: container,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# I. Handling regular serialization of indices, import and export.
+# Import serialization, then re-export.
+
+TestFilesProcess $mytestdir ok serial serial-print -> n label input data expected {
+ test doctools-toc-${impl}-40.$n "doctools::toc deserialize serial, $label, ok" -setup {
+ doctools::toc I
+ } -body {
+ I deserialize = $data
+ I invalidate
+ doctools::toc::structure print [I serialize]
+ } -cleanup {
+ I destroy
+ } -result $expected
+}
+
+# Testing the errors thrown for invalid serializations, at the level
+# of toc objects. Underneath are the doctools::toc::structure
+# commands, so we can and are re-using the test cases which were
+# written for them.
+
+foreach {n badserial expected} {
+ 0 {}
+ {error in serialization: dictionary too short, expected exactly one key}
+ 1 {FOO {}}
+ {error in serialization: bad type tag "FOO"}
+ 2 {doctools::toc {}}
+ {error in serialization: dictionary too short, expected exactly three keys}
+ 3 {doctools::toc {a . b . c .}}
+ {error in serialization: missing expected key "label"}
+ 4 {doctools::toc {label . b . c .}}
+ {error in serialization: missing expected key "title"}
+ 5 {doctools::toc {label . title . c .}}
+ {error in serialization: missing expected key "items"}
+ 7 {doctools::toc {items {{}} label . title .}}
+ {error in serialization: element list wrong, need exactly 2}
+ 8 {doctools::toc {items {{FOO {}}} label . title .}}
+ {error in serialization: bad element tag "FOO"}
+ 9 {doctools::toc {items {{reference {}}} label . title .}}
+ {error in serialization: dictionary too short, expected exactly three keys}
+ 10 {doctools::toc {items {
+ {reference {a . b . c .}}} label . title .}}
+ {error in serialization: missing expected key "id"}
+ 11 {doctools::toc {items {
+ {reference {id . b . c .}}} label . title .}}
+ {error in serialization: missing expected key "label"}
+ 12 {doctools::toc {items {
+ {reference {id . label . c .}}} label . title .}}
+ {error in serialization: missing expected key "desc"}
+ 14 {doctools::toc {items {
+ {division {}}} label . title .}}
+ {error in serialization: dictionary too short, expected two or three keys}
+ 15 {doctools::toc {items {
+ {division {a . b .}}} label . title .}}
+ {error in serialization: missing expected key "label"}
+ 16 {doctools::toc {items {
+ {division {label . b .}}} label . title .}}
+ {error in serialization: missing expected key "items"}
+ 19 {doctools::toc {items {
+ {reference {desc . id . label .}}
+ {reference {desc . id . label .}}} label . title .}}
+ {error in serialization: duplicate labels}
+ 20 {doctools::toc {items {
+ {division {id . items {} label .}}
+ {division {id . items {} label .}}} label . title .}}
+ {error in serialization: duplicate labels}
+ 21 {doctools::toc {items {
+ {division {id . items {} label .}}
+ {reference {desc . id . label .}}} label . title .}}
+ {error in serialization: duplicate labels}
+} {
+ test doctools-toc-${impl}-41.$n "doctools::toc deserialize, error" -setup {
+ doctools::toc I
+ } -body {
+ I deserialize = $badserial
+ } -cleanup {
+ I destroy
+ } -returnCodes error -result $expected
+}
+
+foreach {n noncanonserial expected} {
+ 6 {doctools::toc {label . title . items {}}}
+ {doctools::toc {items {} label . title .}}
+ 13 {doctools::toc {items {
+ {reference {id . label . desc .}}} label . title .}}
+ {doctools::toc {items {{reference {desc . id . label .}}} label . title .}}
+ 17 {doctools::toc {items {
+ {division {label . items {}}}} label . title .}}
+ {doctools::toc {items {{division {items {} label .}}} label . title .}}
+ 18 {doctools::toc {items {
+ {division {items {} label . id .}}} label . title .}}
+ {doctools::toc {items {{division {id . items {} label .}}} label . title .}}
+} {
+ test doctools-toc-${impl}-42.$n "doctools::toc deserialize, regular to canonical" -setup {
+ doctools::toc I
+ I deserialize = $noncanonserial
+ } -body {
+ I serialize
+ } -cleanup {
+ I destroy
+ } -result $expected
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# II. Handling doctoc markup as serialization format, import and export.
+
+# Checking that the various forms of doctoc markup as generated by the
+# export plugin doctools::toc(::export::doctoc) are valid input for
+# the doctoc import plugin. Actually testing that using an import
+# manager from the toc is working.
+
+foreach {k section} {
+ 0 {}
+ 1 -ultracompact
+ 2 -compact
+ 3 -indented
+ 4 -aligned
+ 5 -indalign
+} {
+ TestFilesProcess $mytestdir ok doctoc$section serial-print -> n label input data expected {
+ test doctools-toc-${impl}-50.$k.$n "doctools::toc deserialize = doctoc, $label$section, ok" -setup {
+ doctools::toc I
+ doctools::toc::import IN
+ I importer IN
+ } -body {
+ I deserialize = $data doctoc
+ doctools::toc::structure print [I serialize]
+ } -cleanup {
+ I destroy
+ IN destroy
+ } -result $expected
+ }
+}
+
+# We test the error messages and codes thrown during import for a
+# variety of failure possibilities
+
+TestFilesProcess $mytestdir fail doctoc emsg -> n label input data expected {
+ test doctools-toc-${impl}-51.$n "doctools::toc deserialize = doctoc, $label, error message" -setup {
+ # Basic variables and include search paths for use by the tests
+ doctools::toc::import IN
+ IN config set fox dog
+ IN config set lazy jump
+ IN include add [TestFilesGlob $mytestdir]
+ doctools::toc I
+ I importer IN
+ } -body {
+ I deserialize = $data doctoc
+ } -cleanup {
+ I destroy
+ IN destroy
+ } -returnCodes error -result $expected
+}
+
+TestFilesProcess $mytestdir fail doctoc ecode -> n label input data expected {
+ test doctools-toc-${impl}-52.$n "doctools::toc deserialize = doctoc, $label, error code" -setup {
+ # Basic variables and include search paths for use by the tests
+ doctools::toc::import IN
+ IN config set fox dog
+ IN config set lazy jump
+ IN include add [TestFilesGlob $mytestdir]
+ doctools::toc I
+ I importer IN
+ } -body {
+ catch { I deserialize = $data doctoc }
+ set ::errorCode
+ } -cleanup {
+ I destroy
+ IN destroy
+ } -result $expected
+}
+
+# Testing the export of doctoc markup through attached exporter management, for all possible configurations.
+
+foreach {k nl in al section} {
+ 0 0 0 0 -ultracompact
+ 1 1 0 0 -compact
+ 2 1 1 0 -indented
+ 3 1 0 1 -aligned
+ 4 1 1 1 -indalign
+ 5 0 1 0 -indented
+ 6 0 0 1 -aligned
+ 7 0 1 1 -indalign
+} {
+ TestFilesProcess $mytestdir ok serial doctoc$section -> n label input data expected {
+ test doctools-toc-${impl}-53.$k.$n "doctools::toc serialize doctoc, ${label}$section, ok" -setup {
+ doctools::toc::export OUT
+ OUT config set newlines $nl
+ OUT config set indented $in
+ OUT config set aligned $al
+ doctools::toc I
+ I exporter OUT
+ } -body {
+ I deserialize = $data
+ stripcomments [I serialize doctoc]
+ } -cleanup {
+ I destroy
+ OUT destroy
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# III. Handling text markup as serialization format, export only
+
+TestFilesProcess $mytestdir ok serial text -> n label input data expected {
+ test doctools-toc-${impl}-54.$n "doctools::toc serialize text, $label, ok" -setup {
+ doctools::toc::export OUT
+ doctools::toc I
+ I exporter OUT
+ } -body {
+ I deserialize = $data
+ I serialize text
+ } -cleanup {
+ I destroy
+ OUT destroy
+ } -result $expected
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# IV. Handling json markup as serialization format, import and export.
+
+# We are checking that the various forms of json markup, as can be
+# generated by doctools::toc(::export(::json)) are valid input to the
+# json parser.
+#
+# section {} holds the non-canonical input we have to accept and make
+# canonical to higher layers.
+
+foreach {k section} {
+ 0 {}
+ 1 -ultracompact
+ 2 -indented
+ 3 -indalign
+} {
+ TestFilesProcess $mytestdir ok json$section serial-print -> n label input data expected {
+ test doctools-toc-${impl}-55.$k.$n "doctools::toc deserialize = json, $label$section, ok" -setup {
+ doctools::toc::import IN
+ doctools::toc I
+ I importer IN
+ } -body {
+ I deserialize = $data json
+ doctools::toc::structure print [I serialize]
+ } -cleanup {
+ I destroy
+ IN destroy
+ } -result $expected
+ }
+}
+
+TestFilesProcess $mytestdir fail json json-emsg -> n label input data expected {
+ test doctools-toc-${impl}-56.$n "doctools::toc deserialize = json, $label, error message" -setup {
+ doctools::toc::import IN
+ doctools::toc I
+ I importer IN
+ } -body {
+ I deserialize = $data json
+ } -cleanup {
+ I destroy
+ IN destroy
+ } -returnCodes error -result $expected
+}
+
+foreach {k in al section} {
+ 0 0 0 -ultracompact
+ 1 1 0 -indented
+ 2 0 1 -indalign
+ 3 1 1 -indalign
+} {
+ TestFilesProcess $mytestdir ok serial json$section -> n label input data expected {
+ test doctools-toc-${impl}-57.$k.$n "doctools::toc serialize json, $label$section, ok" -setup {
+ doctools::toc::export OUT
+ OUT config set indented $in
+ OUT config set aligned $al
+ doctools::toc I
+ I exporter OUT
+ } -body {
+ I deserialize = $data
+ I serialize json
+ } -cleanup {
+ I destroy
+ OUT destroy
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# V. Handling html markup as serialization format, export only
+
+foreach {k nl in section} {
+ 0 0 0 -ultracompact
+ 1 0 1 -indented
+ 2 1 0 -compact
+ 3 1 1 -indented
+} {
+ TestFilesProcess $mytestdir ok serial html$section -> n label input data expected {
+ test doctools-toc-${impl}-58.$k.$n "doctools::toc serialize html, $label$section, ok" -setup {
+ doctools::toc::export OUT
+ OUT config set newlines $nl
+ OUT config set indented $in
+ OUT config set user _dummy_
+ doctools::toc I
+ I exporter OUT
+ } -body {
+ I deserialize = $data
+ striphtmlcomments [I serialize html] 3
+ } -cleanup {
+ I destroy
+ OUT destroy
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# VI. Handling wiki markup as serialization format, export only
+
+TestFilesProcess $mytestdir ok serial wiki -> n label input data expected {
+ test doctools-toc-${impl}-59.$n "doctools::toc serialize wiki, $label, ok" -setup {
+ doctools::toc::export OUT
+ doctools::toc I
+ I exporter OUT
+ } -body {
+ I deserialize = $data
+ I serialize wiki
+ } -cleanup {
+ I destroy
+ OUT destroy
+ } -result $expected
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# VII. Handling nroff markup as serialization format, export only
+
+foreach {k inline section} {
+ 0 0 -external
+ 1 1 -inlined
+} {
+ TestFilesProcess $mytestdir ok serial nroff$section -> n label input data expected {
+ test doctools-toc-${impl}-60.$k.$n "doctools::toc serialize nroff, $label$section, ok" -setup {
+ doctools::toc::export OUT
+ OUT config set inline $inline
+ doctools::toc I
+ I exporter OUT
+ } -body {
+ I deserialize = $data
+ stripnroffcomments [stripmanmacros [I serialize nroff]]
+ } -cleanup {
+ I destroy
+ OUT destroy
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+return
+
+# TODO :: Test the merging of indices (copy from toc_structure.test)
+
+# -------------------------------------------------------------------------
+return
diff --git a/tcllib/modules/doctools2toc/tests/container_main b/tcllib/modules/doctools2toc/tests/container_main
new file mode 100644
index 0000000..ce1cc20
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/container_main
@@ -0,0 +1,1003 @@
+
+# -------------------------------------------------------------------------
+
+test doctools-toc-${impl}-1.0 {deserialize =, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I deserialize =
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethoddeserialize_= type selfns win self data ?format?"}
+
+test doctools-toc-${impl}-1.1 {deserialize =, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I deserialize = T F XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethoddeserialize_= type selfns win self data ?format?"}
+
+test doctools-toc-${impl}-2.0 {deserialize +=, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I deserialize +=
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethoddeserialize_+= type selfns win self data ?format?"}
+
+test doctools-toc-${impl}-2.1 {deserialize +=, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I deserialize += T F XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethoddeserialize_+= type selfns win self data ?format?"}
+
+test doctools-toc-${impl}-3.0 {serialize, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I serialize F XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodserialize type selfns win self ?format?"}
+
+test doctools-toc-${impl}-4.0 {+ reference, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I + reference
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethod+_reference type selfns win self pid label docid desc"}
+
+test doctools-toc-${impl}-4.1 {+ reference, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I + reference P
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethod+_reference type selfns win self pid label docid desc"}
+
+test doctools-toc-${impl}-4.2 {+ reference, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I + reference P L
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethod+_reference type selfns win self pid label docid desc"}
+
+test doctools-toc-${impl}-4.3 {+ reference, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I + reference P L D
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethod+_reference type selfns win self pid label docid desc"}
+
+test doctools-toc-${impl}-4.4 {+ reference, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I + reference P L D D XXXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethod+_reference type selfns win self pid label docid desc"}
+
+test doctools-toc-${impl}-5.0 {+ division, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I + division
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethod+_division type selfns win self pid label ?docid?"}
+
+test doctools-toc-${impl}-5.1 {+ division, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I + division P
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethod+_division type selfns win self pid label ?docid?"}
+
+test doctools-toc-${impl}-5.2 {+ division, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I + division P L D XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_hmethod+_division type selfns win self pid label ?docid?"}
+
+test doctools-toc-${impl}-6.0 {remove, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I remove
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodremove type selfns win self id"}
+
+test doctools-toc-${impl}-6.1 {remove, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I remove I XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodremove type selfns win self id"}
+
+test doctools-toc-${impl}-7.0 {up, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I up
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodup type selfns win self id"}
+
+test doctools-toc-${impl}-7.1 {up, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I up I XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodup type selfns win self id"}
+
+test doctools-toc-${impl}-8.0 {next, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I next
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodnext type selfns win self id"}
+
+test doctools-toc-${impl}-8.1 {next, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I next I XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodnext type selfns win self id"}
+
+test doctools-toc-${impl}-9.0 {prev, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I prev
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodprev type selfns win self id"}
+
+test doctools-toc-${impl}-9.1 {prev, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I prev I XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodprev type selfns win self id"}
+
+test doctools-toc-${impl}-10.0 {child, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I child
+} -cleanup {
+ I destroy
+} -returnCodes error -result [tcltest::wrongNumArgs ::doctools::toc::Snit_methodchild {type selfns win self id label args} 0]
+
+test doctools-toc-${impl}-10.1 {child, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I child I
+} -cleanup {
+ I destroy
+} -returnCodes error -result [tcltest::wrongNumArgs ::doctools::toc::Snit_methodchild {type selfns win self id label args} 0]
+
+test doctools-toc-${impl}-11.0 {children, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I children
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodchildren type selfns win self id"}
+
+test doctools-toc-${impl}-11.1 {children, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I children I XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodchildren type selfns win self id"}
+
+test doctools-toc-${impl}-12.0 {type, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I type
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodtype type selfns win self id"}
+
+test doctools-toc-${impl}-12.1 {type, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I type I XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodtype type selfns win self id"}
+
+test doctools-toc-${impl}-13.0 {full-label, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I full-label
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodfull-label type selfns win self id"}
+
+test doctools-toc-${impl}-13.1 {full-label, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I full-label I XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodfull-label type selfns win self id"}
+
+test doctools-toc-${impl}-13.0 {elabel, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I elabel
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodelabel type selfns win self id ?newlabel?"}
+
+test doctools-toc-${impl}-14.1 {elabel, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I elabel I V XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodelabel type selfns win self id ?newlabel?"}
+
+test doctools-toc-${impl}-15.0 {description, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I description
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methoddescription type selfns win self id ?newdesc?"}
+
+test doctools-toc-${impl}-15.1 {description, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I description I V XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methoddescription type selfns win self id ?newdesc?"}
+
+test doctools-toc-${impl}-16.0 {document, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I document
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methoddocument type selfns win self id ?newdocid?"}
+
+test doctools-toc-${impl}-16.1 {document, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I document I V XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methoddocument type selfns win self id ?newdocid?"}
+
+test doctools-toc-${impl}-17.0 {title, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I title T XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodtitle type selfns win self ?text?"}
+
+test doctools-toc-${impl}-18.0 {label, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I label L XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodlabel type selfns win self ?text?"}
+
+test doctools-toc-${impl}-19.0 {exporter, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I exporter E XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodexporter type selfns win self ?object?"}
+
+test doctools-toc-${impl}-20.0 {importer, wrong#args} -setup {
+ doctools::toc I
+} -body {
+ I importer I XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {wrong # args: should be "::doctools::toc::Snit_methodimporter type selfns win self ?object?"}
+
+# -------------------------------------------------------------------------
+
+test doctools-toc-${impl}-21.0 {+ reference, new label} -setup {
+ doctools::toc I
+ set R [I element]
+} -body {
+ I + reference $R L D DESC
+ I children $R
+} -cleanup {
+ I destroy
+ unset R
+} -result node1
+
+test doctools-toc-${impl}-21.1 {+ reference, known key} -setup {
+ doctools::toc I
+ set R [I element]
+ I + reference $R L D DESC
+} -body {
+ I + reference $R L D' DESC'
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {Redefinition of label 'L' in '{}'}
+
+test doctools-toc-${impl}-21.2 {+ reference, not in div} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I + reference $R L' D' DESC'
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {toc element handle 'node1' does not refer to a division}
+
+test doctools-toc-${impl}-21.3 {+ reference, bogus handle} -setup {
+ doctools::toc I
+} -body {
+ I + reference XXX L D DESC
+} -cleanup {
+ I destroy
+} -returnCodes error -result {Bad toc element handle 'XXX'}
+
+test doctools-toc-${impl}-21.4 {+ reference, bogus document id} -setup {
+ doctools::toc I
+ set R [I element]
+} -body {
+ I + reference $R L {} DESC
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {Illegal empty document reference for reference entry}
+
+test doctools-toc-${impl}-22.0 {+ division, new label} -setup {
+ doctools::toc I
+ set R [I element]
+} -body {
+ I + division $R L D
+ I children $R
+} -cleanup {
+ I destroy
+ unset R
+} -result node1
+
+test doctools-toc-${impl}-22.1 {+ division, known key} -setup {
+ doctools::toc I
+ set R [I element]
+ I + division $R L D
+} -body {
+ I + division $R L D'
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {Redefinition of label 'L' in '{}'}
+
+test doctools-toc-${impl}-22.2 {+ division, not in div} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I + division $R L' D'
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {toc element handle 'node1' does not refer to a division}
+
+test doctools-toc-${impl}-22.3 {+ division, bogus handle} -setup {
+ doctools::toc I
+} -body {
+ I + division XXX L D
+} -cleanup {
+ I destroy
+} -returnCodes error -result {Bad toc element handle 'XXX'}
+
+test doctools-toc-${impl}-23.0 {remove, known key, reference} -setup {
+ doctools::toc I
+ set R [I + reference [I element] L D DESC]
+} -body {
+ I remove $R
+ I children [I element]
+} -cleanup {
+ I destroy
+ unset R
+} -result {}
+
+test doctools-toc-${impl}-23.1 {remove, known key, division} -setup {
+ doctools::toc I
+ set R [I + division [I element] L D]
+} -body {
+ I remove $R
+ I children [I element]
+} -cleanup {
+ I destroy
+ unset R
+} -result {}
+
+test doctools-toc-${impl}-23.2 {remove, unknown key} -setup {
+ doctools::toc I
+} -body {
+ I remove XXX
+} -cleanup {
+ I destroy
+} -returnCodes error -result {Bad toc element handle 'XXX'}
+
+test doctools-toc-${impl}-23.3 {remove, root} -setup {
+ doctools::toc I
+} -body {
+ I remove [I element]
+} -cleanup {
+ I destroy
+} -returnCodes error -result {Unable to remove root}
+
+test doctools-toc-${impl}-23.4 {remove, division, children as well} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + division $R L D]
+ set B [I + reference $A L D DESC]
+} -body {
+ I remove $A
+ I type $B
+} -cleanup {
+ I destroy
+ unset R A B
+} -returnCodes error -result {Bad toc element handle 'node2'}
+
+test doctools-toc-${impl}-24.0 {children, nothing} -setup {
+ doctools::toc I
+} -body {
+ I children [I element]
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-${impl}-24.1 {children, something} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + division $R L D]
+} -body {
+ list [llength [I children $R]] \
+ [string equal $A [lindex [I children $R] 0]]
+} -cleanup {
+ I destroy
+ unset R A
+} -result {1 1}
+
+test doctools-toc-${impl}-24.2 {children, multiple, order} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + division $R L D]
+ set B [I + division $R L' D]
+} -body {
+ list [llength [I children $R]] \
+ [string equal $A [lindex [I children $R] 0]] \
+ [string equal $B [lindex [I children $R] 1]]
+} -cleanup {
+ I destroy
+ unset R A B
+} -result {2 1 1}
+
+test doctools-toc-${impl}-25.0 {type, reference} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I type $R
+} -cleanup {
+ I destroy
+ unset R
+} -result reference
+
+test doctools-toc-${impl}-25.1 {type, division} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I type $R
+} -cleanup {
+ I destroy
+ unset R
+} -result division
+
+test doctools-toc-${impl}-26.0 {full-label, reference} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+ set R [I + reference $R L' D DESC]
+} -body {
+ I full-label $R
+} -cleanup {
+ I destroy
+ unset R
+} -result {L L'}
+
+test doctools-toc-${impl}-26.1 {full-label, division} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+ set R [I + division $R L' D]
+} -body {
+ I full-label $R
+} -cleanup {
+ I destroy
+ unset R
+} -result {L L'}
+
+test doctools-toc-${impl}-27.0 {elabel, reference, query} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I elabel $R
+} -cleanup {
+ I destroy
+ unset R
+} -result L
+
+test doctools-toc-${impl}-27.1 {elabel, reference, set, unchanged} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I elabel $R L
+} -cleanup {
+ I destroy
+ unset R
+} -result L
+
+test doctools-toc-${impl}-27.2 {elabel, reference, set, changed} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I elabel $R L'
+} -cleanup {
+ I destroy
+ unset R
+} -result L'
+
+test doctools-toc-${impl}-27.3 {elabel, reference, set, collision} -setup {
+ doctools::toc I
+ set R [I element]
+ I + reference $R L' D DESC
+ set R [I + reference $R L D DESC]
+} -body {
+ I elabel $R L'
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {Redefinition of label 'L'' in '{}'}
+
+test doctools-toc-${impl}-27.4 {elabel, division, query} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I elabel $R
+} -cleanup {
+ I destroy
+ unset R
+} -result L
+
+test doctools-toc-${impl}-27.5 {elabel, division, set, unchanged} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I elabel $R L
+} -cleanup {
+ I destroy
+ unset R
+} -result L
+
+test doctools-toc-${impl}-27.6 {elabel, division, set, changed} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I elabel $R L'
+} -cleanup {
+ I destroy
+ unset R
+} -result L'
+
+test doctools-toc-${impl}-27.7 {elabel, division, set, collision} -setup {
+ doctools::toc I
+ set R [I element]
+ I + division $R L' D
+ set R [I + division $R L D]
+} -body {
+ I elabel $R L'
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {Redefinition of label 'L'' in '{}'}
+
+test doctools-toc-${impl}-28.0 {description, reference, query} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I description $R
+} -cleanup {
+ I destroy
+ unset R
+} -result DESC
+
+test doctools-toc-${impl}-28.1 {description, reference, set, unchanged} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I description $R DESC
+} -cleanup {
+ I destroy
+ unset R
+} -result DESC
+
+test doctools-toc-${impl}-28.2 {description, reference, set, changed} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I description $R DESC'
+} -cleanup {
+ I destroy
+ unset R
+} -result DESC'
+
+test doctools-toc-${impl}-28.3 {description, division, query} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I description $R
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {Divisions have no description}
+
+test doctools-toc-${impl}-28.4 {description, division, set} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I description $R DESC
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {Divisions have no description}
+
+test doctools-toc-${impl}-29.0 {document, reference, query} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I document $R
+} -cleanup {
+ I destroy
+ unset R
+} -result D
+
+test doctools-toc-${impl}-29.1 {document, reference, set, unchanged} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I document $R D
+} -cleanup {
+ I destroy
+ unset R
+} -result D
+
+test doctools-toc-${impl}-29.2 {document, reference, set, changed} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I document $R D'
+} -cleanup {
+ I destroy
+ unset R
+} -result D'
+
+test doctools-toc-${impl}-29.3 {document, reference, set, empty} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + reference $R L D DESC]
+} -body {
+ I document $R {}
+} -cleanup {
+ I destroy
+ unset R
+} -returnCodes error -result {Illegal to unset document reference in reference entry}
+
+test doctools-toc-${impl}-29.4 {document, division, query} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I document $R
+} -cleanup {
+ I destroy
+ unset R
+} -result D
+
+test doctools-toc-${impl}-29.5 {document, division, set, unchanged} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I document $R D
+} -cleanup {
+ I destroy
+ unset R
+} -result D
+
+test doctools-toc-${impl}-29.6 {document, division, set, changed} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I document $R D'
+} -cleanup {
+ I destroy
+ unset R
+} -result D'
+
+test doctools-toc-${impl}-29.7 {document, division, unset} -setup {
+ doctools::toc I
+ set R [I element]
+ set R [I + division $R L D]
+} -body {
+ I document $R {}
+} -cleanup {
+ I destroy
+ unset R
+} -result {}
+
+# -------------------------------------------------------------------------
+
+test doctools-toc-${impl}-30.0 {title, default} -setup {
+ doctools::toc I
+} -body {
+ I title
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-${impl}-30.1 {title, set} -setup {
+ doctools::toc I
+} -body {
+ I title T
+} -cleanup {
+ I destroy
+} -result T
+
+test doctools-toc-${impl}-30.2 {title, get} -setup {
+ doctools::toc I
+ I title T
+} -body {
+ I title
+} -cleanup {
+ I destroy
+} -result T
+
+test doctools-toc-${impl}-31.0 {label, default} -setup {
+ doctools::toc I
+} -body {
+ I label
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-${impl}-31.1 {label, set} -setup {
+ doctools::toc I
+} -body {
+ I label T
+} -cleanup {
+ I destroy
+} -result T
+
+test doctools-toc-${impl}-31.2 {label, get} -setup {
+ doctools::toc I
+ I label T
+} -body {
+ I label
+} -cleanup {
+ I destroy
+} -result T
+
+test doctools-toc-${impl}-32.0 {exporter, default} -setup {
+ doctools::toc I
+} -body {
+ I exporter
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-${impl}-32.1 {exporter, set} -setup {
+ doctools::toc I
+} -body {
+ I exporter T
+} -cleanup {
+ I destroy
+} -result T
+
+test doctools-toc-${impl}-32.2 {exporter, get} -setup {
+ doctools::toc I
+ I exporter T
+} -body {
+ I exporter
+} -cleanup {
+ I destroy
+} -result T
+
+test doctools-toc-${impl}-33.0 {importer, default} -setup {
+ doctools::toc I
+} -body {
+ I importer
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-${impl}-33.1 {importer, set} -setup {
+ doctools::toc I
+} -body {
+ I importer T
+} -cleanup {
+ I destroy
+} -result T
+
+test doctools-toc-${impl}-33.2 {importer, get} -setup {
+ doctools::toc I
+ I importer T
+} -body {
+ I importer
+} -cleanup {
+ I destroy
+} -result T
+
+# -------------------------------------------------------------------------
+
+test doctools-toc-${impl}-34.0 {up, at root} -setup {
+ doctools::toc I
+} -body {
+ I up [I element]
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-${impl}-34.1 {up, at root} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + reference $R L D DESC]
+} -body {
+ string equal $R [I up $A]
+} -cleanup {
+ I destroy
+ unset R A
+} -result 1
+
+test doctools-toc-${impl}-35.0 {next, at root} -setup {
+ doctools::toc I
+} -body {
+ I next [I element]
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-${impl}-35.1 {next, right} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + reference $R L D DESC]
+ set B [I + reference $R L' D' DESC']
+} -body {
+ string equal $B [I next $A]
+} -cleanup {
+ I destroy
+ unset R A B
+} -result 1
+
+test doctools-toc-${impl}-35.2 {next, right up} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + reference $R L D DESC]
+ set B [I + reference $R L' D' DESC']
+} -body {
+ string equal $R [I next $B]
+} -cleanup {
+ I destroy
+ unset R A B
+} -result 1
+
+test doctools-toc-${impl}-36.0 {prev, at root} -setup {
+ doctools::toc I
+} -body {
+ I prev [I element]
+} -cleanup {
+ I destroy
+} -result {}
+
+test doctools-toc-${impl}-36.1 {prev, left} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + reference $R L D DESC]
+ set B [I + reference $R L' D' DESC']
+} -body {
+ string equal $A [I prev $B]
+} -cleanup {
+ I destroy
+ unset R A B
+} -result 1
+
+test doctools-toc-${impl}-36.2 {prev, left up} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + reference $R L D DESC]
+ set B [I + reference $R L' D' DESC']
+} -body {
+ string equal $R [I prev $A]
+} -cleanup {
+ I destroy
+ unset R A B
+} -result 1
+
+test doctools-toc-${impl}-37.0 {child, ok} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + reference $R L D DESC]
+} -body {
+ string equal $A [I child $R L]
+} -cleanup {
+ I destroy
+ unset R A
+} -result 1
+
+test doctools-toc-${impl}-37.1 {child, unknown} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + reference $R L D DESC]
+} -body {
+ I child $R bogus
+} -cleanup {
+ I destroy
+ unset R A
+} -returnCodes error -result {Bad label 'bogus' in '{}'}
+
+test doctools-toc-${impl}-37.2 {child, nested} -setup {
+ doctools::toc I
+ set R [I element]
+ set A [I + division $R L D]
+ set B [I + reference $A L' D' DESC']
+} -body {
+ string equal $B [I child $R L L']
+} -cleanup {
+ I destroy
+ unset R A B
+} -result 1
+
+
+
+# TODO :: check toc merging (+=).
+
+# toc tests, numbering starts at 40
+# -------------------------------------------------------------------------
+
+source [localPath tests/container]
+return
diff --git a/tcllib/modules/doctools2toc/tests/data/bad_command b/tcllib/modules/doctools2toc/tests/data/bad_command
new file mode 100644
index 0000000..8e23fdd
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/bad_command
@@ -0,0 +1 @@
+[item][comment {arguments missing}]
diff --git a/tcllib/modules/doctools2toc/tests/data/empty b/tcllib/modules/doctools2toc/tests/data/empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/empty
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/badtrees.tcl b/tcllib/modules/doctools2toc/tests/data/fail/badtrees.tcl
new file mode 100644
index 0000000..6901e4d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/badtrees.tcl
@@ -0,0 +1,23 @@
+package require struct::tree
+package require fileutil
+
+struct::tree T
+fileutil::writeFile in-vt/0_root_label [T serialize]
+T set root label L
+fileutil::writeFile in-vt/1_root_title [T serialize]
+T set root title T
+T insert root end K
+fileutil::writeFile in-vt/2_keyword_label [T serialize]
+T set K label L
+T insert K end R
+fileutil::writeFile in-vt/3_ref_type [T serialize]
+T set R type foo
+fileutil::writeFile in-vt/4_ref_label [T serialize]
+T set R label L
+fileutil::writeFile in-vt/5_ref_ref [T serialize]
+T set R ref X
+fileutil::writeFile in-vt/6_ref_tag [T serialize]
+T set R type url
+T insert R end OVER
+fileutil::writeFile in-vt/7_depth [T serialize]
+exit
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/01_nonwhitespace1 b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/01_nonwhitespace1
new file mode 100644
index 0000000..5668d0a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/01_nonwhitespace1
@@ -0,0 +1 @@
+regular text is not allowed in toc files \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/02_nonwhitespace2 b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/02_nonwhitespace2
new file mode 100644
index 0000000..edd1d9e
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/02_nonwhitespace2
@@ -0,0 +1 @@
+[vset fox] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/03_illegalcmd1 b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/03_illegalcmd1
new file mode 100644
index 0000000..240d9f7
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/03_illegalcmd1
@@ -0,0 +1 @@
+[foo]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/04_illegalcmd2 b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/04_illegalcmd2
new file mode 100644
index 0000000..893d0d8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/04_illegalcmd2
@@ -0,0 +1 @@
+[vset [foo]] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/05_nestingbad1 b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/05_nestingbad1
new file mode 100644
index 0000000..4682abc
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/05_nestingbad1
@@ -0,0 +1 @@
+[toc_begin a [vset b c]] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/06_nestingbad2 b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/06_nestingbad2
new file mode 100644
index 0000000..bc810a5
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/06_nestingbad2
@@ -0,0 +1 @@
+[toc_begin I [item F L D]] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/07_wrongargs b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/07_wrongargs
new file mode 100644
index 0000000..298f04a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/07_wrongargs
@@ -0,0 +1 @@
+[toc_begin KWIC] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/08_toomanyargs b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/08_toomanyargs
new file mode 100644
index 0000000..ab6569d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/08_toomanyargs
@@ -0,0 +1 @@
+[toc_begin TOC {Table Of Contents} _bogus_] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/09_vsetvarunknown b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/09_vsetvarunknown
new file mode 100644
index 0000000..da33c55
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/09_vsetvarunknown
@@ -0,0 +1 @@
+[vset a] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/10_vsetvarerr b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/10_vsetvarerr
new file mode 100644
index 0000000..122f82d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/10_vsetvarerr
@@ -0,0 +1 @@
+[vset [include bogus] b] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/11_vsetvalueerr b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/11_vsetvalueerr
new file mode 100644
index 0000000..2b7641e
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/11_vsetvalueerr
@@ -0,0 +1 @@
+[vset a [include bogus]] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/12_incerror b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/12_incerror
new file mode 100644
index 0000000..8a40050
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/12_incerror
@@ -0,0 +1 @@
+[include [vset a b]] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/13_incnotfound b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/13_incnotfound
new file mode 100644
index 0000000..e874901
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/13_incnotfound
@@ -0,0 +1 @@
+[include bogus] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/14_incempty b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/14_incempty
new file mode 100644
index 0000000..de07995
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/14_incempty
@@ -0,0 +1 @@
+[include empty] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/15_incbadeof b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/15_incbadeof
new file mode 100644
index 0000000..a093d60
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/15_incbadeof
@@ -0,0 +1 @@
+[include unexpected_eof]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/16_incbadchar b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/16_incbadchar
new file mode 100644
index 0000000..362354c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/16_incbadchar
@@ -0,0 +1 @@
+[include unexpected_char]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/17_badempty b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/17_badempty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/17_badempty
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/18_nobegin b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/18_nobegin
new file mode 100644
index 0000000..db9b03e
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/18_nobegin
@@ -0,0 +1 @@
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/19_manybegin b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/19_manybegin
new file mode 100644
index 0000000..b6a92d2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/19_manybegin
@@ -0,0 +1,5 @@
+[toc_begin A B]
+[toc_begin A B]
+[toc_begin A B]
+[toc_begin A B]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/20_latebegin b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/20_latebegin
new file mode 100644
index 0000000..ea9de89
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/20_latebegin
@@ -0,0 +1,3 @@
+[item F L D]
+[toc_begin A B]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/21_noend1 b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/21_noend1
new file mode 100644
index 0000000..4ebfa77
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/21_noend1
@@ -0,0 +1 @@
+[toc_begin A B]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/22_noend2 b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/22_noend2
new file mode 100644
index 0000000..bafc0eb
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/22_noend2
@@ -0,0 +1,2 @@
+[toc_begin A B]
+[item F L D]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/23_manyend b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/23_manyend
new file mode 100644
index 0000000..93dbd05
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/23_manyend
@@ -0,0 +1,5 @@
+[toc_begin A B]
+[toc_end]
+[toc_end]
+[toc_end]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/24_earlyend b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/24_earlyend
new file mode 100644
index 0000000..528c811
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/24_earlyend
@@ -0,0 +1,4 @@
+[toc_begin A B]
+[toc_end]
+[item F L D]
+
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/25_nobeginend b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/25_nobeginend
new file mode 100644
index 0000000..eb9a7d7
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/25_nobeginend
@@ -0,0 +1,2 @@
+[item F L D]
+[item F L' D']
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/26_nodivbegin b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/26_nodivbegin
new file mode 100644
index 0000000..65e18a2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/26_nodivbegin
@@ -0,0 +1,3 @@
+[toc_begin TOC TOC]
+[division_end]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/27_incbadcmd b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/27_incbadcmd
new file mode 100644
index 0000000..599e5bd
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/27_incbadcmd
@@ -0,0 +1 @@
+[include bad_command] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/28_badredef b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/28_badredef
new file mode 100644
index 0000000..c0d00f8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/28_badredef
@@ -0,0 +1,4 @@
+[toc_begin {Keyword Index} {}]
+[item ID LABEL DESC]
+[item ID LABEL DESC]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/29_badredef2 b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/29_badredef2
new file mode 100644
index 0000000..babe8bd
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/29_badredef2
@@ -0,0 +1,5 @@
+[toc_begin {Keyword Index} {}]
+[item ID LABEL DESC]
+[division_start LABEL]
+[division_end]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/30_manydivbegin b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/30_manydivbegin
new file mode 100644
index 0000000..70d2059
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/30_manydivbegin
@@ -0,0 +1,5 @@
+[toc_begin TOC TOC]
+[division_start L F]
+[division_start L F]
+[division_start L F]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/31_nodivend b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/31_nodivend
new file mode 100644
index 0000000..bef23d3
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/31_nodivend
@@ -0,0 +1,3 @@
+[toc_begin TOC TOC]
+[division_start L F]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/doctoc/32_manydivend b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/32_manydivend
new file mode 100644
index 0000000..b1e3ff6
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/doctoc/32_manydivend
@@ -0,0 +1,5 @@
+[toc_begin TOC TOC]
+[division_end]
+[division_end]
+[division_end]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/01_nonwhitespace1 b/tcllib/modules/doctools2toc/tests/data/fail/ecode/01_nonwhitespace1
new file mode 100644
index 0000000..b52db63
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/01_nonwhitespace1
@@ -0,0 +1 @@
+{{} {0 39} 1 40 doctoc/plaintext {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/02_nonwhitespace2 b/tcllib/modules/doctools2toc/tests/data/fail/ecode/02_nonwhitespace2
new file mode 100644
index 0000000..a810f91
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/02_nonwhitespace2
@@ -0,0 +1 @@
+{{} {1 4} 1 5 doctoc/plaintext {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/03_illegalcmd1 b/tcllib/modules/doctools2toc/tests/data/fail/ecode/03_illegalcmd1
new file mode 100644
index 0000000..23676aa
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/03_illegalcmd1
@@ -0,0 +1 @@
+{{} {1 3} 1 4 doctoc/cmd/illegal foo}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/04_illegalcmd2 b/tcllib/modules/doctools2toc/tests/data/fail/ecode/04_illegalcmd2
new file mode 100644
index 0000000..76a957a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/04_illegalcmd2
@@ -0,0 +1 @@
+{{} {7 9} 1 10 doctoc/cmd/illegal foo}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/05_nestingbad1 b/tcllib/modules/doctools2toc/tests/data/fail/ecode/05_nestingbad1
new file mode 100644
index 0000000..e4728c5
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/05_nestingbad1
@@ -0,0 +1 @@
+{{} {14 17} 1 18 doctoc/cmd/nested vset/2}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/06_nestingbad2 b/tcllib/modules/doctools2toc/tests/data/fail/ecode/06_nestingbad2
new file mode 100644
index 0000000..80fa726
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/06_nestingbad2
@@ -0,0 +1 @@
+{{} {14 17} 1 18 doctoc/cmd/nested item}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/07_wrongargs b/tcllib/modules/doctools2toc/tests/data/fail/ecode/07_wrongargs
new file mode 100644
index 0000000..53f47c0
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/07_wrongargs
@@ -0,0 +1 @@
+{{} {1 9} 1 10 doctoc/cmd/wrongargs {toc_begin 2}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/08_toomanyargs b/tcllib/modules/doctools2toc/tests/data/fail/ecode/08_toomanyargs
new file mode 100644
index 0000000..b9ade4d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/08_toomanyargs
@@ -0,0 +1 @@
+{{} {1 9} 1 10 doctoc/cmd/toomanyargs {toc_begin 2}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/09_vsetvarunknown b/tcllib/modules/doctools2toc/tests/data/fail/ecode/09_vsetvarunknown
new file mode 100644
index 0000000..c95a1c0
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/09_vsetvarunknown
@@ -0,0 +1 @@
+{{} {1 4} 1 5 doctoc/vset/varname/unknown a}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/10_vsetvarerr b/tcllib/modules/doctools2toc/tests/data/fail/ecode/10_vsetvarerr
new file mode 100644
index 0000000..e133089
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/10_vsetvarerr
@@ -0,0 +1 @@
+{{} {7 13} 1 14 doctoc/cmd/nested include}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/11_vsetvalueerr b/tcllib/modules/doctools2toc/tests/data/fail/ecode/11_vsetvalueerr
new file mode 100644
index 0000000..e21599c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/11_vsetvalueerr
@@ -0,0 +1 @@
+{{} {9 15} 1 16 doctoc/cmd/nested include}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/12_incerror b/tcllib/modules/doctools2toc/tests/data/fail/ecode/12_incerror
new file mode 100644
index 0000000..03610bb
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/12_incerror
@@ -0,0 +1 @@
+{{} {10 13} 1 14 doctoc/cmd/nested vset/2}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/13_incnotfound b/tcllib/modules/doctools2toc/tests/data/fail/ecode/13_incnotfound
new file mode 100644
index 0000000..4b9fe3a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/13_incnotfound
@@ -0,0 +1 @@
+{{} {1 7} 1 8 doctoc/include/path/notfound bogus}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/14_incempty b/tcllib/modules/doctools2toc/tests/data/fail/ecode/14_incempty
new file mode 100644
index 0000000..dcf238b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/14_incempty
@@ -0,0 +1 @@
+{{} {0 0} 1 0 doctoc/toc_begin/missing {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/15_incbadeof b/tcllib/modules/doctools2toc/tests/data/fail/ecode/15_incbadeof
new file mode 100644
index 0000000..328f512
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/15_incbadeof
@@ -0,0 +1 @@
+{{} {1 7} 1 8 doctoc/include/syntax {@/tests/data/unexpected_eof {{{} {27 27} 1 27 doctoc/eof/syntax {}}}}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/16_incbadchar b/tcllib/modules/doctools2toc/tests/data/fail/ecode/16_incbadchar
new file mode 100644
index 0000000..44f268b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/16_incbadchar
@@ -0,0 +1 @@
+{{} {1 7} 1 8 doctoc/include/syntax {@/tests/data/unexpected_char {{{} {27 27} 1 27 doctoc/char/syntax {}}}}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/17_badempty b/tcllib/modules/doctools2toc/tests/data/fail/ecode/17_badempty
new file mode 100644
index 0000000..dcf238b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/17_badempty
@@ -0,0 +1 @@
+{{} {0 0} 1 0 doctoc/toc_begin/missing {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/18_nobegin b/tcllib/modules/doctools2toc/tests/data/fail/ecode/18_nobegin
new file mode 100644
index 0000000..d9ca877
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/18_nobegin
@@ -0,0 +1 @@
+{{} {1 7} 1 8 doctoc/toc_begin/missing {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/19_manybegin b/tcllib/modules/doctools2toc/tests/data/fail/ecode/19_manybegin
new file mode 100644
index 0000000..058a824
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/19_manybegin
@@ -0,0 +1 @@
+{{} {17 25} 2 10 doctoc/toc_begin/syntax {}} {{} {33 41} 3 10 doctoc/toc_begin/syntax {}} {{} {49 57} 4 10 doctoc/toc_begin/syntax {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/20_latebegin b/tcllib/modules/doctools2toc/tests/data/fail/ecode/20_latebegin
new file mode 100644
index 0000000..70cfffe
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/20_latebegin
@@ -0,0 +1 @@
+{{} {1 4} 1 5 doctoc/toc_begin/missing {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/21_noend1 b/tcllib/modules/doctools2toc/tests/data/fail/ecode/21_noend1
new file mode 100644
index 0000000..08f3435
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/21_noend1
@@ -0,0 +1 @@
+{{} {1 9} 1 10 doctoc/toc_end/missing {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/22_noend2 b/tcllib/modules/doctools2toc/tests/data/fail/ecode/22_noend2
new file mode 100644
index 0000000..47da638
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/22_noend2
@@ -0,0 +1 @@
+{{} {17 20} 2 5 doctoc/toc_end/missing {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/23_manyend b/tcllib/modules/doctools2toc/tests/data/fail/ecode/23_manyend
new file mode 100644
index 0000000..aa37c55
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/23_manyend
@@ -0,0 +1 @@
+{{} {27 33} 3 8 doctoc/toc_end/syntax {}} {{} {37 43} 4 8 doctoc/toc_end/syntax {}} {{} {47 53} 5 8 doctoc/toc_end/syntax {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/24_earlyend b/tcllib/modules/doctools2toc/tests/data/fail/ecode/24_earlyend
new file mode 100644
index 0000000..9d05b9d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/24_earlyend
@@ -0,0 +1 @@
+{{} {27 30} 3 5 doctoc/item/syntax {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/25_nobeginend b/tcllib/modules/doctools2toc/tests/data/fail/ecode/25_nobeginend
new file mode 100644
index 0000000..8d3d1b9
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/25_nobeginend
@@ -0,0 +1 @@
+{{} {1 4} 1 5 doctoc/toc_begin/missing {}} {{} {14 17} 2 5 doctoc/toc_begin/missing {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/26_nodivbegin b/tcllib/modules/doctools2toc/tests/data/fail/ecode/26_nodivbegin
new file mode 100644
index 0000000..cc7ea87
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/26_nodivbegin
@@ -0,0 +1 @@
+{{} {21 32} 2 13 doctoc/division_end/syntax {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/27_incbadcmd b/tcllib/modules/doctools2toc/tests/data/fail/ecode/27_incbadcmd
new file mode 100644
index 0000000..08048d2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/27_incbadcmd
@@ -0,0 +1 @@
+{@/tests/data/bad_command {1 4} 1 5 doctoc/cmd/wrongargs {item 3}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/28_badredef b/tcllib/modules/doctools2toc/tests/data/fail/ecode/28_badredef
new file mode 100644
index 0000000..7b81c93
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/28_badredef
@@ -0,0 +1 @@
+{{} {53 56} 3 5 doctoc/redef LABEL}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/29_badredef2 b/tcllib/modules/doctools2toc/tests/data/fail/ecode/29_badredef2
new file mode 100644
index 0000000..4b3cc09
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/29_badredef2
@@ -0,0 +1 @@
+{{} {53 66} 3 15 doctoc/redef LABEL} \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/30_manydivbegin b/tcllib/modules/doctools2toc/tests/data/fail/ecode/30_manydivbegin
new file mode 100644
index 0000000..c085d4b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/30_manydivbegin
@@ -0,0 +1 @@
+{{} {84 90} 5 8 doctoc/division_end/missing {}} {{} {84 90} 5 8 doctoc/toc_end/syntax {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/31_nodivend b/tcllib/modules/doctools2toc/tests/data/fail/ecode/31_nodivend
new file mode 100644
index 0000000..26012a6
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/31_nodivend
@@ -0,0 +1 @@
+{{} {42 48} 3 8 doctoc/division_end/missing {}} {{} {42 48} 3 8 doctoc/toc_end/syntax {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/ecode/32_manydivend b/tcllib/modules/doctools2toc/tests/data/fail/ecode/32_manydivend
new file mode 100644
index 0000000..dfc74d9
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/ecode/32_manydivend
@@ -0,0 +1 @@
+{{} {21 32} 2 13 doctoc/division_end/syntax {}} {{} {36 47} 3 13 doctoc/division_end/syntax {}} {{} {51 62} 4 13 doctoc/division_end/syntax {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/01_nonwhitespace1 b/tcllib/modules/doctools2toc/tests/data/fail/emsg/01_nonwhitespace1
new file mode 100644
index 0000000..a026582
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/01_nonwhitespace1
@@ -0,0 +1 @@
+error on line 1.40: Plain text beyond whitespace is not allowed
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/02_nonwhitespace2 b/tcllib/modules/doctools2toc/tests/data/fail/emsg/02_nonwhitespace2
new file mode 100644
index 0000000..fe97361
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/02_nonwhitespace2
@@ -0,0 +1 @@
+error on line 1.5: Plain text beyond whitespace is not allowed
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/03_illegalcmd1 b/tcllib/modules/doctools2toc/tests/data/fail/emsg/03_illegalcmd1
new file mode 100644
index 0000000..20bc922
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/03_illegalcmd1
@@ -0,0 +1 @@
+error on line 1.4: Illegal command "foo", not a doctoc command
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/04_illegalcmd2 b/tcllib/modules/doctools2toc/tests/data/fail/emsg/04_illegalcmd2
new file mode 100644
index 0000000..3ad9935
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/04_illegalcmd2
@@ -0,0 +1 @@
+error on line 1.10: Illegal command "foo", not a doctoc command
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/05_nestingbad1 b/tcllib/modules/doctools2toc/tests/data/fail/emsg/05_nestingbad1
new file mode 100644
index 0000000..e65e334
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/05_nestingbad1
@@ -0,0 +1 @@
+error on line 1.18: Illegal use of "vset/2" as argument of other command
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/06_nestingbad2 b/tcllib/modules/doctools2toc/tests/data/fail/emsg/06_nestingbad2
new file mode 100644
index 0000000..fcf4cdc
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/06_nestingbad2
@@ -0,0 +1 @@
+error on line 1.18: Illegal use of "item" as argument of other command
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/07_wrongargs b/tcllib/modules/doctools2toc/tests/data/fail/emsg/07_wrongargs
new file mode 100644
index 0000000..3326719
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/07_wrongargs
@@ -0,0 +1 @@
+error on line 1.10: Wrong#args for "toc_begin", need at least 2
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/08_toomanyargs b/tcllib/modules/doctools2toc/tests/data/fail/emsg/08_toomanyargs
new file mode 100644
index 0000000..efe705a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/08_toomanyargs
@@ -0,0 +1 @@
+error on line 1.10: Too many args for "toc_begin", at most 2 allowed
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/09_vsetvarunknown b/tcllib/modules/doctools2toc/tests/data/fail/emsg/09_vsetvarunknown
new file mode 100644
index 0000000..f73a6bc
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/09_vsetvarunknown
@@ -0,0 +1 @@
+error on line 1.5: Unknown variable "a"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/10_vsetvarerr b/tcllib/modules/doctools2toc/tests/data/fail/emsg/10_vsetvarerr
new file mode 100644
index 0000000..cf07b85
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/10_vsetvarerr
@@ -0,0 +1 @@
+error on line 1.14: Illegal use of "include" as argument of other command
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/11_vsetvalueerr b/tcllib/modules/doctools2toc/tests/data/fail/emsg/11_vsetvalueerr
new file mode 100644
index 0000000..13eefe5
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/11_vsetvalueerr
@@ -0,0 +1 @@
+error on line 1.16: Illegal use of "include" as argument of other command
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/12_incerror b/tcllib/modules/doctools2toc/tests/data/fail/emsg/12_incerror
new file mode 100644
index 0000000..644618d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/12_incerror
@@ -0,0 +1 @@
+error on line 1.14: Illegal use of "vset/2" as argument of other command
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/13_incnotfound b/tcllib/modules/doctools2toc/tests/data/fail/emsg/13_incnotfound
new file mode 100644
index 0000000..3750a26
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/13_incnotfound
@@ -0,0 +1 @@
+error on line 1.8: Include file "bogus" not found
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/14_incempty b/tcllib/modules/doctools2toc/tests/data/fail/emsg/14_incempty
new file mode 100644
index 0000000..3b1db20
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/14_incempty
@@ -0,0 +1 @@
+error on line 1.0: Expected [toc_begin], not found
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/15_incbadeof b/tcllib/modules/doctools2toc/tests/data/fail/emsg/15_incbadeof
new file mode 100644
index 0000000..390567b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/15_incbadeof
@@ -0,0 +1,2 @@
+error on line 1.8: Errors in include file "@/tests/data/unexpected_eof"
+"@/tests/data/unexpected_eof": error on line 1.27: Bad <eof>
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/16_incbadchar b/tcllib/modules/doctools2toc/tests/data/fail/emsg/16_incbadchar
new file mode 100644
index 0000000..7666aa2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/16_incbadchar
@@ -0,0 +1,2 @@
+error on line 1.8: Errors in include file "@/tests/data/unexpected_char"
+"@/tests/data/unexpected_char": error on line 1.27: Bad character in string
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/17_badempty b/tcllib/modules/doctools2toc/tests/data/fail/emsg/17_badempty
new file mode 100644
index 0000000..3b1db20
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/17_badempty
@@ -0,0 +1 @@
+error on line 1.0: Expected [toc_begin], not found
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/18_nobegin b/tcllib/modules/doctools2toc/tests/data/fail/emsg/18_nobegin
new file mode 100644
index 0000000..31511ea
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/18_nobegin
@@ -0,0 +1 @@
+error on line 1.8: Expected [toc_begin], not found
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/19_manybegin b/tcllib/modules/doctools2toc/tests/data/fail/emsg/19_manybegin
new file mode 100644
index 0000000..ea6385a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/19_manybegin
@@ -0,0 +1,3 @@
+error on line 2.10: Unexpected [toc_begin], not allowed here
+error on line 3.10: Unexpected [toc_begin], not allowed here
+error on line 4.10: Unexpected [toc_begin], not allowed here
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/20_latebegin b/tcllib/modules/doctools2toc/tests/data/fail/emsg/20_latebegin
new file mode 100644
index 0000000..b4db5b7
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/20_latebegin
@@ -0,0 +1,2 @@
+error on line 1.5: Expected [toc_begin], not found
+
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/21_noend1 b/tcllib/modules/doctools2toc/tests/data/fail/emsg/21_noend1
new file mode 100644
index 0000000..b981fc1
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/21_noend1
@@ -0,0 +1 @@
+error on line 1.10: Expected [toc_end], not found
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/22_noend2 b/tcllib/modules/doctools2toc/tests/data/fail/emsg/22_noend2
new file mode 100644
index 0000000..385ca45
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/22_noend2
@@ -0,0 +1 @@
+error on line 2.5: Expected [toc_end], not found
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/23_manyend b/tcllib/modules/doctools2toc/tests/data/fail/emsg/23_manyend
new file mode 100644
index 0000000..1fa20b7
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/23_manyend
@@ -0,0 +1,3 @@
+error on line 3.8: Unexpected [toc_end], not allowed here
+error on line 4.8: Unexpected [toc_end], not allowed here
+error on line 5.8: Unexpected [toc_end], not allowed here
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/24_earlyend b/tcllib/modules/doctools2toc/tests/data/fail/emsg/24_earlyend
new file mode 100644
index 0000000..12d3db9
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/24_earlyend
@@ -0,0 +1 @@
+error on line 3.5: Unexpected [item], not allowed here
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/25_nobeginend b/tcllib/modules/doctools2toc/tests/data/fail/emsg/25_nobeginend
new file mode 100644
index 0000000..9cf6486
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/25_nobeginend
@@ -0,0 +1,2 @@
+error on line 1.5: Expected [toc_begin], not found
+error on line 2.5: Expected [toc_begin], not found
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/26_nodivbegin b/tcllib/modules/doctools2toc/tests/data/fail/emsg/26_nodivbegin
new file mode 100644
index 0000000..5a174f8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/26_nodivbegin
@@ -0,0 +1 @@
+error on line 2.13: Unexpected [division_end], not allowed here
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/27_incbadcmd b/tcllib/modules/doctools2toc/tests/data/fail/emsg/27_incbadcmd
new file mode 100644
index 0000000..23dea3b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/27_incbadcmd
@@ -0,0 +1 @@
+"@/tests/data/bad_command" error on line 1.5: Wrong#args for "item", need at least 3
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/28_badredef b/tcllib/modules/doctools2toc/tests/data/fail/emsg/28_badredef
new file mode 100644
index 0000000..d26a6f2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/28_badredef
@@ -0,0 +1 @@
+error on line 3.5: Bad reuse of label "LABEL"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/29_badredef2 b/tcllib/modules/doctools2toc/tests/data/fail/emsg/29_badredef2
new file mode 100644
index 0000000..fe10c28
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/29_badredef2
@@ -0,0 +1 @@
+error on line 3.15: Bad reuse of label "LABEL"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/30_manydivbegin b/tcllib/modules/doctools2toc/tests/data/fail/emsg/30_manydivbegin
new file mode 100644
index 0000000..3e3a123
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/30_manydivbegin
@@ -0,0 +1,2 @@
+error on line 5.8: Expected [division_end], not found
+error on line 5.8: Unexpected [toc_end], not allowed here
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/31_nodivend b/tcllib/modules/doctools2toc/tests/data/fail/emsg/31_nodivend
new file mode 100644
index 0000000..424cd8f
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/31_nodivend
@@ -0,0 +1,2 @@
+error on line 3.8: Expected [division_end], not found
+error on line 3.8: Unexpected [toc_end], not allowed here
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/emsg/32_manydivend b/tcllib/modules/doctools2toc/tests/data/fail/emsg/32_manydivend
new file mode 100644
index 0000000..0cecb94
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/emsg/32_manydivend
@@ -0,0 +1,3 @@
+error on line 2.13: Unexpected [division_end], not allowed here
+error on line 3.13: Unexpected [division_end], not allowed here
+error on line 4.13: Unexpected [division_end], not allowed here
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/00_short b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/00_short
new file mode 100644
index 0000000..4329caa
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/00_short
@@ -0,0 +1 @@
+error in serialization: dictionary too short, expected exactly one key
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/01_tag b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/01_tag
new file mode 100644
index 0000000..369116b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/01_tag
@@ -0,0 +1 @@
+error in serialization: bad type tag "FOO"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/02_cshort b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/02_cshort
new file mode 100644
index 0000000..2dbe5b7
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/02_cshort
@@ -0,0 +1 @@
+error in serialization: dictionary too short, expected exactly three keys
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/03_misslabel b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/03_misslabel
new file mode 100644
index 0000000..3c3da93
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/03_misslabel
@@ -0,0 +1 @@
+error in serialization: missing expected key "label"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/04_misstitle b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/04_misstitle
new file mode 100644
index 0000000..8401b05
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/04_misstitle
@@ -0,0 +1 @@
+error in serialization: missing expected key "title"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/05_missitems b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/05_missitems
new file mode 100644
index 0000000..50331bd
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/05_missitems
@@ -0,0 +1 @@
+error in serialization: missing expected key "items"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/07_cshort2 b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/07_cshort2
new file mode 100644
index 0000000..29f072a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/07_cshort2
@@ -0,0 +1 @@
+error in serialization: element list wrong, need exactly 2 \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/08_etag b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/08_etag
new file mode 100644
index 0000000..21a0f0a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/08_etag
@@ -0,0 +1 @@
+error in serialization: bad element tag "FOO"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/09_cshort3 b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/09_cshort3
new file mode 100644
index 0000000..e753b96
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/09_cshort3
@@ -0,0 +1,2 @@
+error in serialization: dictionary too short, expected exactly three keys
+
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/10_missid b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/10_missid
new file mode 100644
index 0000000..deac041
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/10_missid
@@ -0,0 +1 @@
+error in serialization: missing expected key "id"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/11_misslabel2 b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/11_misslabel2
new file mode 100644
index 0000000..55d919d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/11_misslabel2
@@ -0,0 +1,2 @@
+error in serialization: missing expected key "label"
+
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/12_missdesc b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/12_missdesc
new file mode 100644
index 0000000..7a8c4c3
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/12_missdesc
@@ -0,0 +1,2 @@
+error in serialization: missing expected key "desc"
+
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/14_dshort b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/14_dshort
new file mode 100644
index 0000000..e1abdb2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/14_dshort
@@ -0,0 +1,2 @@
+error in serialization: dictionary too short, expected two or three keys
+
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/15_misslabel3 b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/15_misslabel3
new file mode 100644
index 0000000..c5f7daa
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/15_misslabel3
@@ -0,0 +1,3 @@
+error in serialization: missing expected key "label"
+
+
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/16_missitems2 b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/16_missitems2
new file mode 100644
index 0000000..50331bd
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/16_missitems2
@@ -0,0 +1 @@
+error in serialization: missing expected key "items"
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/19_duplabel b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/19_duplabel
new file mode 100644
index 0000000..9a9863a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/19_duplabel
@@ -0,0 +1 @@
+error in serialization: duplicate labels \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/20_duplabel2 b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/20_duplabel2
new file mode 100644
index 0000000..9a9863a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/20_duplabel2
@@ -0,0 +1 @@
+error in serialization: duplicate labels \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/21_duplabel3 b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/21_duplabel3
new file mode 100644
index 0000000..9a9863a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json-emsg/21_duplabel3
@@ -0,0 +1 @@
+error in serialization: duplicate labels \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/00_short b/tcllib/modules/doctools2toc/tests/data/fail/json/00_short
new file mode 100644
index 0000000..2c63c08
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/00_short
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/01_tag b/tcllib/modules/doctools2toc/tests/data/fail/json/01_tag
new file mode 100644
index 0000000..9803dba
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/01_tag
@@ -0,0 +1,4 @@
+{
+ "FOO" : {
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/02_cshort b/tcllib/modules/doctools2toc/tests/data/fail/json/02_cshort
new file mode 100644
index 0000000..325b934
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/02_cshort
@@ -0,0 +1,4 @@
+{
+ "doctools::toc" : {
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/03_misslabel b/tcllib/modules/doctools2toc/tests/data/fail/json/03_misslabel
new file mode 100644
index 0000000..e08662c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/03_misslabel
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "a" : ".",
+ "b" : ".",
+ "c" : "."
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/04_misstitle b/tcllib/modules/doctools2toc/tests/data/fail/json/04_misstitle
new file mode 100644
index 0000000..ec1eaa8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/04_misstitle
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "b" : ".",
+ "c" : "."
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/05_missitems b/tcllib/modules/doctools2toc/tests/data/fail/json/05_missitems
new file mode 100644
index 0000000..4c4e391
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/05_missitems
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "c" : "."
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/07_cshort2 b/tcllib/modules/doctools2toc/tests/data/fail/json/07_cshort2
new file mode 100644
index 0000000..f99a165
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/07_cshort2
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/08_etag b/tcllib/modules/doctools2toc/tests/data/fail/json/08_etag
new file mode 100644
index 0000000..b43a43b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/08_etag
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "FOO" : ""}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/09_cshort3 b/tcllib/modules/doctools2toc/tests/data/fail/json/09_cshort3
new file mode 100644
index 0000000..c7ac012
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/09_cshort3
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "reference" : ""}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/10_missid b/tcllib/modules/doctools2toc/tests/data/fail/json/10_missid
new file mode 100644
index 0000000..c249aec
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/10_missid
@@ -0,0 +1,11 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "reference" : {
+ "a" : ".",
+ "b" : ".",
+ "c" : "."
+ }}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/11_misslabel2 b/tcllib/modules/doctools2toc/tests/data/fail/json/11_misslabel2
new file mode 100644
index 0000000..401f608
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/11_misslabel2
@@ -0,0 +1,11 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "reference" : {
+ "id" : ".",
+ "b" : ".",
+ "c" : "."
+ }}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/12_missdesc b/tcllib/modules/doctools2toc/tests/data/fail/json/12_missdesc
new file mode 100644
index 0000000..a0824f2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/12_missdesc
@@ -0,0 +1,11 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "reference" : {
+ "id" : ".",
+ "label" : ".",
+ "c" : "."
+ }}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/14_dshort b/tcllib/modules/doctools2toc/tests/data/fail/json/14_dshort
new file mode 100644
index 0000000..a71bba0
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/14_dshort
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "division" : ""}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/15_misslabel3 b/tcllib/modules/doctools2toc/tests/data/fail/json/15_misslabel3
new file mode 100644
index 0000000..1c70099
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/15_misslabel3
@@ -0,0 +1,10 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "division" : {
+ "a" : ".",
+ "b" : "."
+ }}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/16_missitems2 b/tcllib/modules/doctools2toc/tests/data/fail/json/16_missitems2
new file mode 100644
index 0000000..d4437de
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/16_missitems2
@@ -0,0 +1,10 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "division" : {
+ "label" : ".",
+ "b" : "."
+ }}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/19_duplabel b/tcllib/modules/doctools2toc/tests/data/fail/json/19_duplabel
new file mode 100644
index 0000000..1b7d921
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/19_duplabel
@@ -0,0 +1,15 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "reference" : {
+ "id" : ".",
+ "label" : ".",
+ "desc" : "."
+ }},{ "reference" : {
+ "id" : ".",
+ "label" : ".",
+ "desc" : "."
+ }}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/20_duplabel2 b/tcllib/modules/doctools2toc/tests/data/fail/json/20_duplabel2
new file mode 100644
index 0000000..9335518
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/20_duplabel2
@@ -0,0 +1,15 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "division" : {
+ "id" : ".",
+ "label" : ".",
+ "items" : ""
+ }},{ "division" : {
+ "id" : ".",
+ "label" : ".",
+ "items" : ""
+ }}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/fail/json/21_duplabel3 b/tcllib/modules/doctools2toc/tests/data/fail/json/21_duplabel3
new file mode 100644
index 0000000..b802d3f
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/fail/json/21_duplabel3
@@ -0,0 +1,15 @@
+{
+ "doctools::toc" : {
+ "label" : ".",
+ "title" : ".",
+ "items" : [{ "reference" : {
+ "id" : ".",
+ "label" : ".",
+ "desc" : "."
+ }},{ "division" : {
+ "id" : ".",
+ "label" : ".",
+ "items" : ""
+ }}]
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/1_empty
new file mode 100644
index 0000000..6f5db06
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/1_empty
@@ -0,0 +1,2 @@
+[toc_begin TOC TOC]
+[toc_end] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/2_references b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/2_references
new file mode 100644
index 0000000..3e5ab89
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/2_references
@@ -0,0 +1,5 @@
+[toc_begin {Table of Contents} {}]
+[item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+[item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/3_toc
new file mode 100644
index 0000000..63f1b1c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/3_toc
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+[item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[division_start Processing processing.man]
+[item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+[division_end]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/4_toc2
new file mode 100644
index 0000000..398718c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-aligned/4_toc2
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+[item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[division_start Processing processing.man]
+[item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+[division_end]
+[item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/1_empty
new file mode 100644
index 0000000..6f5db06
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/1_empty
@@ -0,0 +1,2 @@
+[toc_begin TOC TOC]
+[toc_end] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/2_references b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/2_references
new file mode 100644
index 0000000..9432e62
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/2_references
@@ -0,0 +1,5 @@
+[toc_begin {Table of Contents} {}]
+[item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+[item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/3_toc
new file mode 100644
index 0000000..28896ac
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/3_toc
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+[item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[division_start Processing processing.man]
+[item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+[division_end]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/4_toc2
new file mode 100644
index 0000000..8ca535b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-compact/4_toc2
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+[item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[division_start Processing processing.man]
+[item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+[division_end]
+[item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/1_empty
new file mode 100644
index 0000000..6f5db06
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/1_empty
@@ -0,0 +1,2 @@
+[toc_begin TOC TOC]
+[toc_end] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/2_references b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/2_references
new file mode 100644
index 0000000..978be38
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/2_references
@@ -0,0 +1,5 @@
+[toc_begin {Table of Contents} {}]
+ [item structure.man doctools::toc::structure {doctoc serialization utilities}]
+ [item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+ [item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/3_toc
new file mode 100644
index 0000000..49a43d6
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/3_toc
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+ [item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+ [division_start Processing processing.man]
+ [item structure.man doctools::toc::structure {doctoc serialization utilities}]
+ [item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+ [division_end]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/4_toc2
new file mode 100644
index 0000000..596bf3e
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indalign/4_toc2
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+ [item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+ [division_start Processing processing.man]
+ [item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+ [division_end]
+ [item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/1_empty
new file mode 100644
index 0000000..a4f2ffd
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/1_empty
@@ -0,0 +1,2 @@
+[toc_begin TOC TOC]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/2_references b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/2_references
new file mode 100644
index 0000000..7d72fd5
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/2_references
@@ -0,0 +1,5 @@
+[toc_begin {Table of Contents} {}]
+ [item structure.man doctools::toc::structure {doctoc serialization utilities}]
+ [item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+ [item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/3_toc
new file mode 100644
index 0000000..e048067
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/3_toc
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+ [item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+ [division_start Processing processing.man]
+ [item structure.man doctools::toc::structure {doctoc serialization utilities}]
+ [item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+ [division_end]
+[toc_end] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/4_toc2
new file mode 100644
index 0000000..000d2b6
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-indented/4_toc2
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+ [item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+ [division_start Processing processing.man]
+ [item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+ [division_end]
+ [item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/1_empty
new file mode 100644
index 0000000..24f98d4
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/1_empty
@@ -0,0 +1 @@
+[toc_begin TOC TOC][toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/2_references b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/2_references
new file mode 100644
index 0000000..69183d2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/2_references
@@ -0,0 +1 @@
+[toc_begin {Table of Contents} {}][item structure.man doctools::toc::structure {doctoc serialization utilities}][item parse.man doctools::toc::parse {Parsing text in doctoc format}][item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}][toc_end] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/3_toc
new file mode 100644
index 0000000..9a679ed
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/3_toc
@@ -0,0 +1 @@
+[toc_begin {Table of Contents} TOC][item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}][division_start Processing processing.man][item structure.man doctools::toc::structure {doctoc serialization utilities}][item parse.man doctools::toc::parse {Parsing text in doctoc format}][division_end][toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/4_toc2
new file mode 100644
index 0000000..a42ba63
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc-ultracompact/4_toc2
@@ -0,0 +1 @@
+[toc_begin {Table of Contents} TOC][item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}][division_start Processing processing.man][item parse.man doctools::toc::parse {Parsing text in doctoc format}][division_end][item structure.man doctools::toc::structure {doctoc serialization utilities}][toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/doctoc/1_empty
new file mode 100644
index 0000000..6f5db06
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc/1_empty
@@ -0,0 +1,2 @@
+[toc_begin TOC TOC]
+[toc_end] \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc/2_references b/tcllib/modules/doctools2toc/tests/data/ok/doctoc/2_references
new file mode 100644
index 0000000..9432e62
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc/2_references
@@ -0,0 +1,5 @@
+[toc_begin {Table of Contents} {}]
+[item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+[item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/doctoc/3_toc
new file mode 100644
index 0000000..63f1b1c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc/3_toc
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+[item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[division_start Processing processing.man]
+[item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+[division_end]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/doctoc/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/doctoc/4_toc2
new file mode 100644
index 0000000..217342d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/doctoc/4_toc2
@@ -0,0 +1,7 @@
+[toc_begin {Table of Contents} TOC]
+[item introduction.man doctools::toc::introduction {DocTools - Tables of Contents}]
+[division_start Processing processing.man]
+[item parse.man doctools::toc::parse {Parsing text in doctoc format}]
+[division_end]
+[item structure.man doctools::toc::structure {doctoc serialization utilities}]
+[toc_end]
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-compact/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/html-compact/1_empty
new file mode 100644
index 0000000..e886a56
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-compact/1_empty
@@ -0,0 +1,20 @@
+<html>
+<head>
+<title>TOC -- TOC</title>
+<style></style>
+</head>
+
+<body>
+<div class="doctools">
+<div class="toc-header">
+<h1 class="toc-title">TOC -- TOC</h1>
+<!-- Customization Point: header -->
+<hr class="toc-navsep">
+</div>
+<div class="toc-footer">
+<hr class="toc-navsep">
+<!-- Customization Point: footer -->
+</div>
+</div>
+</body>
+</html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-compact/2_references b/tcllib/modules/doctools2toc/tests/data/ok/html-compact/2_references
new file mode 100644
index 0000000..f366e63
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-compact/2_references
@@ -0,0 +1,30 @@
+<html>
+<head>
+<title>Table of Contents</title>
+<style></style>
+</head>
+
+<body>
+<div class="doctools">
+<div class="toc-header">
+<h1 class="toc-title">Table of Contents</h1>
+<!-- Customization Point: header -->
+<hr class="toc-navsep">
+</div>
+<!-- - Start Table Of Contents ---------------------------------- -->
+<dl class="toc-contents">
+<dt class="toc-ref"><a href="structure.man">doctools::toc::structure</a></dt>
+<dd class="toc-ref">doctoc serialization utilities</dd>
+<dt class="toc-ref"><a href="parse.man">doctools::toc::parse</a></dt>
+<dd class="toc-ref">Parsing text in doctoc format</dd>
+<dt class="toc-ref"><a href="introduction.man">doctools::toc::introduction</a></dt>
+<dd class="toc-ref">DocTools - Tables of Contents</dd>
+</dl>
+<!-- - Stop Table Of Contents ---------------------------------- -->
+<div class="toc-footer">
+<hr class="toc-navsep">
+<!-- Customization Point: footer -->
+</div>
+</div>
+</body>
+</html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-compact/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/html-compact/3_toc
new file mode 100644
index 0000000..d765d38
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-compact/3_toc
@@ -0,0 +1,37 @@
+<html>
+<head>
+<title>Table of Contents -- TOC</title>
+<style></style>
+</head>
+
+<body>
+<div class="doctools">
+<div class="toc-header">
+<h1 class="toc-title">Table of Contents -- TOC</h1>
+<!-- Customization Point: header -->
+<hr class="toc-navsep">
+</div>
+<!-- - Start Table Of Contents ---------------------------------- -->
+<dl class="toc-contents">
+<dt class="toc-ref"><a href="introduction.man">doctools::toc::introduction</a></dt>
+<dd class="toc-ref">DocTools - Tables of Contents</dd>
+<dt class="toc-div"><a href="processing.man">Processing</a></dt>
+<dd class="toc-div">
+<!-- - Start Division (Processing) ------------------------------ -->
+<dl class="toc-contents">
+<dt class="toc-ref"><a href="structure.man">doctools::toc::structure</a></dt>
+<dd class="toc-ref">doctoc serialization utilities</dd>
+<dt class="toc-ref"><a href="parse.man">doctools::toc::parse</a></dt>
+<dd class="toc-ref">Parsing text in doctoc format</dd>
+</dl>
+<!-- - Stop Division (Processing) ------------------------------ -->
+</dd>
+</dl>
+<!-- - Stop Table Of Contents ---------------------------------- -->
+<div class="toc-footer">
+<hr class="toc-navsep">
+<!-- Customization Point: footer -->
+</div>
+</div>
+</body>
+</html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-compact/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/html-compact/4_toc2
new file mode 100644
index 0000000..11b2cd0
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-compact/4_toc2
@@ -0,0 +1,37 @@
+<html>
+<head>
+<title>Table of Contents -- TOC</title>
+<style></style>
+</head>
+
+<body>
+<div class="doctools">
+<div class="toc-header">
+<h1 class="toc-title">Table of Contents -- TOC</h1>
+<!-- Customization Point: header -->
+<hr class="toc-navsep">
+</div>
+<!-- - Start Table Of Contents ---------------------------------- -->
+<dl class="toc-contents">
+<dt class="toc-ref"><a href="introduction.man">doctools::toc::introduction</a></dt>
+<dd class="toc-ref">DocTools - Tables of Contents</dd>
+<dt class="toc-div"><a href="processing.man">Processing</a></dt>
+<dd class="toc-div">
+<!-- - Start Division (Processing) ------------------------------ -->
+<dl class="toc-contents">
+<dt class="toc-ref"><a href="parse.man">doctools::toc::parse</a></dt>
+<dd class="toc-ref">Parsing text in doctoc format</dd>
+</dl>
+<!-- - Stop Division (Processing) ------------------------------ -->
+</dd>
+<dt class="toc-ref"><a href="structure.man">doctools::toc::structure</a></dt>
+<dd class="toc-ref">doctoc serialization utilities</dd>
+</dl>
+<!-- - Stop Table Of Contents ---------------------------------- -->
+<div class="toc-footer">
+<hr class="toc-navsep">
+<!-- Customization Point: footer -->
+</div>
+</div>
+</body>
+</html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-indented/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/html-indented/1_empty
new file mode 100644
index 0000000..08be800
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-indented/1_empty
@@ -0,0 +1,20 @@
+<html>
+ <head>
+ <title>TOC -- TOC</title>
+ <style></style>
+ </head>
+
+ <body>
+ <div class="doctools">
+ <div class="toc-header">
+ <h1 class="toc-title">TOC -- TOC</h1>
+ <!-- Customization Point: header -->
+ <hr class="toc-navsep">
+ </div>
+ <div class="toc-footer">
+ <hr class="toc-navsep">
+ <!-- Customization Point: footer -->
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-indented/2_references b/tcllib/modules/doctools2toc/tests/data/ok/html-indented/2_references
new file mode 100644
index 0000000..ac834d9
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-indented/2_references
@@ -0,0 +1,30 @@
+<html>
+ <head>
+ <title>Table of Contents</title>
+ <style></style>
+ </head>
+
+ <body>
+ <div class="doctools">
+ <div class="toc-header">
+ <h1 class="toc-title">Table of Contents</h1>
+ <!-- Customization Point: header -->
+ <hr class="toc-navsep">
+ </div>
+ <!-- - Start Table Of Contents ---------------------------------- -->
+ <dl class="toc-contents">
+ <dt class="toc-ref"><a href="structure.man">doctools::toc::structure</a></dt>
+ <dd class="toc-ref">doctoc serialization utilities</dd>
+ <dt class="toc-ref"><a href="parse.man">doctools::toc::parse</a></dt>
+ <dd class="toc-ref">Parsing text in doctoc format</dd>
+ <dt class="toc-ref"><a href="introduction.man">doctools::toc::introduction</a></dt>
+ <dd class="toc-ref">DocTools - Tables of Contents</dd>
+ </dl>
+ <!-- - Stop Table Of Contents ---------------------------------- -->
+ <div class="toc-footer">
+ <hr class="toc-navsep">
+ <!-- Customization Point: footer -->
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-indented/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/html-indented/3_toc
new file mode 100644
index 0000000..1fb5f5a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-indented/3_toc
@@ -0,0 +1,37 @@
+<html>
+ <head>
+ <title>Table of Contents -- TOC</title>
+ <style></style>
+ </head>
+
+ <body>
+ <div class="doctools">
+ <div class="toc-header">
+ <h1 class="toc-title">Table of Contents -- TOC</h1>
+ <!-- Customization Point: header -->
+ <hr class="toc-navsep">
+ </div>
+ <!-- - Start Table Of Contents ---------------------------------- -->
+ <dl class="toc-contents">
+ <dt class="toc-ref"><a href="introduction.man">doctools::toc::introduction</a></dt>
+ <dd class="toc-ref">DocTools - Tables of Contents</dd>
+ <dt class="toc-div"><a href="processing.man">Processing</a></dt>
+ <dd class="toc-div">
+ <!-- - Start Division (Processing) ------------------------------ -->
+ <dl class="toc-contents">
+ <dt class="toc-ref"><a href="structure.man">doctools::toc::structure</a></dt>
+ <dd class="toc-ref">doctoc serialization utilities</dd>
+ <dt class="toc-ref"><a href="parse.man">doctools::toc::parse</a></dt>
+ <dd class="toc-ref">Parsing text in doctoc format</dd>
+ </dl>
+ <!-- - Stop Division (Processing) ------------------------------ -->
+ </dd>
+ </dl>
+ <!-- - Stop Table Of Contents ---------------------------------- -->
+ <div class="toc-footer">
+ <hr class="toc-navsep">
+ <!-- Customization Point: footer -->
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-indented/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/html-indented/4_toc2
new file mode 100644
index 0000000..85f664d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-indented/4_toc2
@@ -0,0 +1,37 @@
+<html>
+ <head>
+ <title>Table of Contents -- TOC</title>
+ <style></style>
+ </head>
+
+ <body>
+ <div class="doctools">
+ <div class="toc-header">
+ <h1 class="toc-title">Table of Contents -- TOC</h1>
+ <!-- Customization Point: header -->
+ <hr class="toc-navsep">
+ </div>
+ <!-- - Start Table Of Contents ---------------------------------- -->
+ <dl class="toc-contents">
+ <dt class="toc-ref"><a href="introduction.man">doctools::toc::introduction</a></dt>
+ <dd class="toc-ref">DocTools - Tables of Contents</dd>
+ <dt class="toc-div"><a href="processing.man">Processing</a></dt>
+ <dd class="toc-div">
+ <!-- - Start Division (Processing) ------------------------------ -->
+ <dl class="toc-contents">
+ <dt class="toc-ref"><a href="parse.man">doctools::toc::parse</a></dt>
+ <dd class="toc-ref">Parsing text in doctoc format</dd>
+ </dl>
+ <!-- - Stop Division (Processing) ------------------------------ -->
+ </dd>
+ <dt class="toc-ref"><a href="structure.man">doctools::toc::structure</a></dt>
+ <dd class="toc-ref">doctoc serialization utilities</dd>
+ </dl>
+ <!-- - Stop Table Of Contents ---------------------------------- -->
+ <div class="toc-footer">
+ <hr class="toc-navsep">
+ <!-- Customization Point: footer -->
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/1_empty
new file mode 100644
index 0000000..14aa774
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/1_empty
@@ -0,0 +1 @@
+<html><head><title>TOC -- TOC</title><style></style></head><body><div class="doctools"><div class="toc-header"><h1 class="toc-title">TOC -- TOC</h1><hr class="toc-navsep"></div><div class="toc-footer"><hr class="toc-navsep"></div></div></body></html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/2_references b/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/2_references
new file mode 100644
index 0000000..f6d5312
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/2_references
@@ -0,0 +1 @@
+<html><head><title>Table of Contents</title><style></style></head><body><div class="doctools"><div class="toc-header"><h1 class="toc-title">Table of Contents</h1><hr class="toc-navsep"></div><dl class="toc-contents"><dt class="toc-ref"><a href="structure.man">doctools::toc::structure</a></dt><dd class="toc-ref">doctoc serialization utilities</dd><dt class="toc-ref"><a href="parse.man">doctools::toc::parse</a></dt><dd class="toc-ref">Parsing text in doctoc format</dd><dt class="toc-ref"><a href="introduction.man">doctools::toc::introduction</a></dt><dd class="toc-ref">DocTools - Tables of Contents</dd></dl><div class="toc-footer"><hr class="toc-navsep"></div></div></body></html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/3_toc
new file mode 100644
index 0000000..3e9828d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/3_toc
@@ -0,0 +1 @@
+<html><head><title>Table of Contents -- TOC</title><style></style></head><body><div class="doctools"><div class="toc-header"><h1 class="toc-title">Table of Contents -- TOC</h1><hr class="toc-navsep"></div><dl class="toc-contents"><dt class="toc-ref"><a href="introduction.man">doctools::toc::introduction</a></dt><dd class="toc-ref">DocTools - Tables of Contents</dd><dt class="toc-div"><a href="processing.man">Processing</a></dt><dd class="toc-div"><dl class="toc-contents"><dt class="toc-ref"><a href="structure.man">doctools::toc::structure</a></dt><dd class="toc-ref">doctoc serialization utilities</dd><dt class="toc-ref"><a href="parse.man">doctools::toc::parse</a></dt><dd class="toc-ref">Parsing text in doctoc format</dd></dl></dd></dl><div class="toc-footer"><hr class="toc-navsep"></div></div></body></html>
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/4_toc2
new file mode 100644
index 0000000..04f4c39
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/html-ultracompact/4_toc2
@@ -0,0 +1 @@
+<html><head><title>Table of Contents -- TOC</title><style></style></head><body><div class="doctools"><div class="toc-header"><h1 class="toc-title">Table of Contents -- TOC</h1><hr class="toc-navsep"></div><dl class="toc-contents"><dt class="toc-ref"><a href="introduction.man">doctools::toc::introduction</a></dt><dd class="toc-ref">DocTools - Tables of Contents</dd><dt class="toc-div"><a href="processing.man">Processing</a></dt><dd class="toc-div"><dl class="toc-contents"><dt class="toc-ref"><a href="parse.man">doctools::toc::parse</a></dt><dd class="toc-ref">Parsing text in doctoc format</dd></dl></dd><dt class="toc-ref"><a href="structure.man">doctools::toc::structure</a></dt><dd class="toc-ref">doctoc serialization utilities</dd></dl><div class="toc-footer"><hr class="toc-navsep"></div></div></body></html> \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/1_empty
new file mode 100644
index 0000000..766b40c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/1_empty
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "items" : [],
+ "label" : "TOC",
+ "title" : "TOC"
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/2_references b/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/2_references
new file mode 100644
index 0000000..19ab697
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/2_references
@@ -0,0 +1,25 @@
+{
+ "doctools::toc" : {
+ "items" : [{
+ "reference" : {
+ "desc" : "doctoc serialization utilities",
+ "id" : "structure.man",
+ "label" : "doctools::toc::structure"
+ }
+ },{
+ "reference" : {
+ "desc" : "Parsing text in doctoc format",
+ "id" : "parse.man",
+ "label" : "doctools::toc::parse"
+ }
+ },{
+ "reference" : {
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man",
+ "label" : "doctools::toc::introduction"
+ }
+ }],
+ "label" : "Table of Contents",
+ "title" : ""
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/3_toc
new file mode 100644
index 0000000..3ad6339
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/3_toc
@@ -0,0 +1,31 @@
+{
+ "doctools::toc" : {
+ "items" : [{
+ "reference" : {
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man",
+ "label" : "doctools::toc::introduction"
+ }
+ },{
+ "division" : {
+ "id" : "processing.man",
+ "items" : [{
+ "reference" : {
+ "desc" : "doctoc serialization utilities",
+ "id" : "structure.man",
+ "label" : "doctools::toc::structure"
+ }
+ },{
+ "reference" : {
+ "desc" : "Parsing text in doctoc format",
+ "id" : "parse.man",
+ "label" : "doctools::toc::parse"
+ }
+ }],
+ "label" : "Processing"
+ }
+ }],
+ "label" : "Table of Contents",
+ "title" : "TOC"
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/4_toc2
new file mode 100644
index 0000000..8779d95
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-indalign/4_toc2
@@ -0,0 +1,31 @@
+{
+ "doctools::toc" : {
+ "items" : [{
+ "reference" : {
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man",
+ "label" : "doctools::toc::introduction"
+ }
+ },{
+ "division" : {
+ "id" : "processing.man",
+ "items" : [{
+ "reference" : {
+ "desc" : "Parsing text in doctoc format",
+ "id" : "parse.man",
+ "label" : "doctools::toc::parse"
+ }
+ }],
+ "label" : "Processing"
+ }
+ },{
+ "reference" : {
+ "desc" : "doctoc serialization utilities",
+ "id" : "structure.man",
+ "label" : "doctools::toc::structure"
+ }
+ }],
+ "label" : "Table of Contents",
+ "title" : "TOC"
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-indented/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/json-indented/1_empty
new file mode 100644
index 0000000..766b40c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-indented/1_empty
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "items" : [],
+ "label" : "TOC",
+ "title" : "TOC"
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-indented/2_references b/tcllib/modules/doctools2toc/tests/data/ok/json-indented/2_references
new file mode 100644
index 0000000..c3adb97
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-indented/2_references
@@ -0,0 +1,25 @@
+{
+ "doctools::toc" : {
+ "items" : [{
+ "reference" : {
+ "desc" : "doctoc serialization utilities",
+ "id" : "structure.man",
+ "label" : "doctools::toc::structure"
+ }
+ },{
+ "reference" : {
+ "desc" : "Parsing text in doctoc format",
+ "id" : "parse.man",
+ "label" : "doctools::toc::parse"
+ }
+ },{
+ "reference" : {
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man",
+ "label" : "doctools::toc::introduction"
+ }
+ }],
+ "label" : "Table of Contents",
+ "title" : ""
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-indented/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/json-indented/3_toc
new file mode 100644
index 0000000..2364953
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-indented/3_toc
@@ -0,0 +1,31 @@
+{
+ "doctools::toc" : {
+ "items" : [{
+ "reference" : {
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man",
+ "label" : "doctools::toc::introduction"
+ }
+ },{
+ "division" : {
+ "id" : "processing.man",
+ "items" : [{
+ "reference" : {
+ "desc" : "doctoc serialization utilities",
+ "id" : "structure.man",
+ "label" : "doctools::toc::structure"
+ }
+ },{
+ "reference" : {
+ "desc" : "Parsing text in doctoc format",
+ "id" : "parse.man",
+ "label" : "doctools::toc::parse"
+ }
+ }],
+ "label" : "Processing"
+ }
+ }],
+ "label" : "Table of Contents",
+ "title" : "TOC"
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-indented/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/json-indented/4_toc2
new file mode 100644
index 0000000..958bf12
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-indented/4_toc2
@@ -0,0 +1,31 @@
+{
+ "doctools::toc" : {
+ "items" : [{
+ "reference" : {
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man",
+ "label" : "doctools::toc::introduction"
+ }
+ },{
+ "division" : {
+ "id" : "processing.man",
+ "items" : [{
+ "reference" : {
+ "desc" : "Parsing text in doctoc format",
+ "id" : "parse.man",
+ "label" : "doctools::toc::parse"
+ }
+ }],
+ "label" : "Processing"
+ }
+ },{
+ "reference" : {
+ "desc" : "doctoc serialization utilities",
+ "id" : "structure.man",
+ "label" : "doctools::toc::structure"
+ }
+ }],
+ "label" : "Table of Contents",
+ "title" : "TOC"
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/1_empty
new file mode 100644
index 0000000..3b4e072
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/1_empty
@@ -0,0 +1 @@
+{"doctools::toc":{"items":[],"label":"TOC","title":"TOC"}}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/2_references b/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/2_references
new file mode 100644
index 0000000..304256f
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/2_references
@@ -0,0 +1 @@
+{"doctools::toc":{"items":[{"reference":{"desc":"doctoc serialization utilities","id":"structure.man","label":"doctools::toc::structure"}},{"reference":{"desc":"Parsing text in doctoc format","id":"parse.man","label":"doctools::toc::parse"}},{"reference":{"desc":"DocTools - Tables of Contents","id":"introduction.man","label":"doctools::toc::introduction"}}],"label":"Table of Contents","title":""}}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/3_toc
new file mode 100644
index 0000000..d40b45d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/3_toc
@@ -0,0 +1 @@
+{"doctools::toc":{"items":[{"reference":{"desc":"DocTools - Tables of Contents","id":"introduction.man","label":"doctools::toc::introduction"}},{"division":{"id":"processing.man","items":[{"reference":{"desc":"doctoc serialization utilities","id":"structure.man","label":"doctools::toc::structure"}},{"reference":{"desc":"Parsing text in doctoc format","id":"parse.man","label":"doctools::toc::parse"}}],"label":"Processing"}}],"label":"Table of Contents","title":"TOC"}}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/4_toc2
new file mode 100644
index 0000000..d130f98
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json-ultracompact/4_toc2
@@ -0,0 +1 @@
+{"doctools::toc":{"items":[{"reference":{"desc":"DocTools - Tables of Contents","id":"introduction.man","label":"doctools::toc::introduction"}},{"division":{"id":"processing.man","items":[{"reference":{"desc":"Parsing text in doctoc format","id":"parse.man","label":"doctools::toc::parse"}}],"label":"Processing"}},{"reference":{"desc":"doctoc serialization utilities","id":"structure.man","label":"doctools::toc::structure"}}],"label":"Table of Contents","title":"TOC"}} \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/json/1_empty
new file mode 100644
index 0000000..5f852ac
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json/1_empty
@@ -0,0 +1,7 @@
+{
+ "doctools::toc" : {
+ "label" : "TOC",
+ "title" : "TOC",
+ "items" : []
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json/2_references b/tcllib/modules/doctools2toc/tests/data/ok/json/2_references
new file mode 100644
index 0000000..8e7510e
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json/2_references
@@ -0,0 +1,25 @@
+{
+ "doctools::toc" : {
+ "title" : "",
+ "items" : [{
+ "reference" : {
+ "id" : "structure.man",
+ "desc" : "doctoc serialization utilities",
+ "label" : "doctools::toc::structure"
+ }
+ },{
+ "reference" : {
+ "id" : "parse.man",
+ "desc" : "Parsing text in doctoc format",
+ "label" : "doctools::toc::parse"
+ }
+ },{
+ "reference" : {
+ "label" : "doctools::toc::introduction",
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man"
+ }
+ }],
+ "label" : "Table of Contents"
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/json/3_toc
new file mode 100644
index 0000000..925a932
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json/3_toc
@@ -0,0 +1,31 @@
+{
+ "doctools::toc" : {
+ "label" : "Table of Contents",
+ "items" : [{
+ "reference" : {
+ "label" : "doctools::toc::introduction",
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man"
+ }
+ },{
+ "division" : {
+ "items" : [{
+ "reference" : {
+ "id" : "structure.man",
+ "desc" : "doctoc serialization utilities",
+ "label" : "doctools::toc::structure"
+ }
+ },{
+ "reference" : {
+ "label" : "doctools::toc::parse",
+ "desc" : "Parsing text in doctoc format",
+ "id" : "parse.man"
+ }
+ }],
+ "label" : "Processing",
+ "id" : "processing.man"
+ }
+ }],
+ "title" : "TOC"
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/json/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/json/4_toc2
new file mode 100644
index 0000000..55ff761
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/json/4_toc2
@@ -0,0 +1,31 @@
+{
+ "doctools::toc" : {
+ "label" : "Table of Contents",
+ "items" : [{
+ "reference" : {
+ "label" : "doctools::toc::introduction",
+ "desc" : "DocTools - Tables of Contents",
+ "id" : "introduction.man"
+ }
+ },{
+ "division" : {
+ "items" : [{
+ "reference" : {
+ "label" : "doctools::toc::parse",
+ "desc" : "Parsing text in doctoc format",
+ "id" : "parse.man"
+ }
+ }],
+ "label" : "Processing",
+ "id" : "processing.man"
+ }
+ },{
+ "reference" : {
+ "id" : "structure.man",
+ "desc" : "doctoc serialization utilities",
+ "label" : "doctools::toc::structure"
+ }
+ }],
+ "title" : "TOC"
+ }
+}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/1_empty
new file mode 100644
index 0000000..1c01c52
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/1_empty
@@ -0,0 +1,4 @@
+.so man.macros
+.TH TOC
+.SH "TABLE OF CONTENTS"
+TOC
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/2_references b/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/2_references
new file mode 100644
index 0000000..23285cf
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/2_references
@@ -0,0 +1,14 @@
+.so man.macros
+.TH "TABLE OF CONTENTS"
+.SH "TABLE OF CONTENTS"
+.RS
+.TP
+\fBdoctools::toc::structure\fR
+doctoc serialization utilities
+.TP
+\fBdoctools::toc::parse\fR
+Parsing text in doctoc format
+.TP
+\fBdoctools::toc::introduction\fR
+DocTools - Tables of Contents
+.RE
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/3_toc
new file mode 100644
index 0000000..b738407
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/3_toc
@@ -0,0 +1,19 @@
+.so man.macros
+.TH "TABLE OF CONTENTS"
+.SH "TABLE OF CONTENTS"
+TOC
+.RS
+.TP
+\fBdoctools::toc::introduction\fR
+DocTools - Tables of Contents
+.TP
+\fBProcessing\fR
+.RS
+.TP
+\fBdoctools::toc::structure\fR
+doctoc serialization utilities
+.TP
+\fBdoctools::toc::parse\fR
+Parsing text in doctoc format
+.RE
+.RE
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/4_toc2
new file mode 100644
index 0000000..4df0548
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/nroff-external/4_toc2
@@ -0,0 +1,19 @@
+.so man.macros
+.TH "TABLE OF CONTENTS"
+.SH "TABLE OF CONTENTS"
+TOC
+.RS
+.TP
+\fBdoctools::toc::introduction\fR
+DocTools - Tables of Contents
+.TP
+\fBProcessing\fR
+.RS
+.TP
+\fBdoctools::toc::parse\fR
+Parsing text in doctoc format
+.RE
+.TP
+\fBdoctools::toc::structure\fR
+doctoc serialization utilities
+.RE
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/1_empty
new file mode 100644
index 0000000..668c866
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/1_empty
@@ -0,0 +1,3 @@
+.TH TOC
+.SH "TABLE OF CONTENTS"
+TOC
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/2_references b/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/2_references
new file mode 100644
index 0000000..7a55c89
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/2_references
@@ -0,0 +1,13 @@
+.TH "TABLE OF CONTENTS"
+.SH "TABLE OF CONTENTS"
+.RS
+.TP
+\fBdoctools::toc::structure\fR
+doctoc serialization utilities
+.TP
+\fBdoctools::toc::parse\fR
+Parsing text in doctoc format
+.TP
+\fBdoctools::toc::introduction\fR
+DocTools - Tables of Contents
+.RE
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/3_toc
new file mode 100644
index 0000000..b4cc5f8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/3_toc
@@ -0,0 +1,18 @@
+.TH "TABLE OF CONTENTS"
+.SH "TABLE OF CONTENTS"
+TOC
+.RS
+.TP
+\fBdoctools::toc::introduction\fR
+DocTools - Tables of Contents
+.TP
+\fBProcessing\fR
+.RS
+.TP
+\fBdoctools::toc::structure\fR
+doctoc serialization utilities
+.TP
+\fBdoctools::toc::parse\fR
+Parsing text in doctoc format
+.RE
+.RE
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/4_toc2
new file mode 100644
index 0000000..6a470f7
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/nroff-inlined/4_toc2
@@ -0,0 +1,18 @@
+.TH "TABLE OF CONTENTS"
+.SH "TABLE OF CONTENTS"
+TOC
+.RS
+.TP
+\fBdoctools::toc::introduction\fR
+DocTools - Tables of Contents
+.TP
+\fBProcessing\fR
+.RS
+.TP
+\fBdoctools::toc::parse\fR
+Parsing text in doctoc format
+.RE
+.TP
+\fBdoctools::toc::structure\fR
+doctoc serialization utilities
+.RE
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/serial-print/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/serial-print/1_empty
new file mode 100644
index 0000000..31ec2ff
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/serial-print/1_empty
@@ -0,0 +1 @@
+doctools::toc TOC TOC
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/serial-print/2_references b/tcllib/modules/doctools2toc/tests/data/ok/serial-print/2_references
new file mode 100644
index 0000000..f80e088
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/serial-print/2_references
@@ -0,0 +1,4 @@
+doctools::toc {Table of Contents} {}
+....structure.man doctools::toc::structure {doctoc serialization utilities}
+....parse.man doctools::toc::parse {Parsing text in doctoc format}
+....introduction.man doctools::toc::introduction {DocTools - Tables of Contents}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/serial-print/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/serial-print/3_toc
new file mode 100644
index 0000000..032b764
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/serial-print/3_toc
@@ -0,0 +1,5 @@
+doctools::toc {Table of Contents} TOC
+....introduction.man doctools::toc::introduction {DocTools - Tables of Contents}
+....processing.man Processing
+........structure.man doctools::toc::structure {doctoc serialization utilities}
+........parse.man doctools::toc::parse {Parsing text in doctoc format}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/serial-print/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/serial-print/4_toc2
new file mode 100644
index 0000000..b493406
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/serial-print/4_toc2
@@ -0,0 +1,5 @@
+doctools::toc {Table of Contents} TOC
+....introduction.man doctools::toc::introduction {DocTools - Tables of Contents}
+....processing.man Processing
+........parse.man doctools::toc::parse {Parsing text in doctoc format}
+....structure.man doctools::toc::structure {doctoc serialization utilities}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/serial/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/serial/1_empty
new file mode 100644
index 0000000..0b06b3d
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/serial/1_empty
@@ -0,0 +1 @@
+doctools::toc {items {} label TOC title TOC}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/serial/2_references b/tcllib/modules/doctools2toc/tests/data/ok/serial/2_references
new file mode 100644
index 0000000..3ef0355
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/serial/2_references
@@ -0,0 +1 @@
+doctools::toc {items {{reference {desc {doctoc serialization utilities} id structure.man label doctools::toc::structure}} {reference {desc {Parsing text in doctoc format} id parse.man label doctools::toc::parse}} {reference {desc {DocTools - Tables of Contents} id introduction.man label doctools::toc::introduction}}} label {Table of Contents} title {}}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/serial/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/serial/3_toc
new file mode 100644
index 0000000..796d1c2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/serial/3_toc
@@ -0,0 +1,2 @@
+doctools::toc {items {{reference {desc {DocTools - Tables of Contents} id introduction.man label doctools::toc::introduction}} {division {id processing.man items {{reference {desc {doctoc serialization utilities} id structure.man label doctools::toc::structure}} {reference {desc {Parsing text in doctoc format} id parse.man label doctools::toc::parse}}} label Processing}}} label {Table of Contents} title TOC}
+
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/serial/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/serial/4_toc2
new file mode 100644
index 0000000..1d9c2d1
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/serial/4_toc2
@@ -0,0 +1 @@
+doctools::toc {items {{reference {desc {DocTools - Tables of Contents} id introduction.man label doctools::toc::introduction}} {division {id processing.man items {{reference {desc {Parsing text in doctoc format} id parse.man label doctools::toc::parse}}} label Processing}} {reference {desc {doctoc serialization utilities} id structure.man label doctools::toc::structure}}} label {Table of Contents} title TOC}
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/text/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/text/1_empty
new file mode 100644
index 0000000..954d944
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/text/1_empty
@@ -0,0 +1,2 @@
+TOC -- TOC
+==========
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/text/2_references b/tcllib/modules/doctools2toc/tests/data/ok/text/2_references
new file mode 100644
index 0000000..539c8e8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/text/2_references
@@ -0,0 +1,11 @@
+Table of Contents
+=================
+
+structure.man : doctools::toc::structure
+ doctoc serialization utilities
+
+parse.man : doctools::toc::parse
+ Parsing text in doctoc format
+
+introduction.man : doctools::toc::introduction
+ DocTools - Tables of Contents
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/text/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/text/3_toc
new file mode 100644
index 0000000..452f02f
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/text/3_toc
@@ -0,0 +1,14 @@
+Table of Contents -- TOC
+========================
+
+introduction.man : doctools::toc::introduction
+ DocTools - Tables of Contents
+
+processing.man : Processing
+---------------------------
+
+ structure.man : doctools::toc::structure
+ doctoc serialization utilities
+
+ parse.man : doctools::toc::parse
+ Parsing text in doctoc format
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/text/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/text/4_toc2
new file mode 100644
index 0000000..dbcd94b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/text/4_toc2
@@ -0,0 +1,15 @@
+Table of Contents -- TOC
+========================
+
+introduction.man : doctools::toc::introduction
+ DocTools - Tables of Contents
+
+processing.man : Processing
+---------------------------
+
+ parse.man : doctools::toc::parse
+ Parsing text in doctoc format
+
+
+structure.man : doctools::toc::structure
+ doctoc serialization utilities
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/wiki/1_empty b/tcllib/modules/doctools2toc/tests/data/ok/wiki/1_empty
new file mode 100644
index 0000000..7de7984
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/wiki/1_empty
@@ -0,0 +1 @@
+**TOC -- TOC**
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/wiki/2_references b/tcllib/modules/doctools2toc/tests/data/ok/wiki/2_references
new file mode 100644
index 0000000..867aec8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/wiki/2_references
@@ -0,0 +1,5 @@
+**Table of Contents**
+
+ * [structure.man%|%doctools::toc::structure] : doctoc serialization utilities
+ * [parse.man%|%doctools::toc::parse] : Parsing text in doctoc format
+ * [introduction.man%|%doctools::toc::introduction] : DocTools - Tables of Contents
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/wiki/3_toc b/tcllib/modules/doctools2toc/tests/data/ok/wiki/3_toc
new file mode 100644
index 0000000..6cde073
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/wiki/3_toc
@@ -0,0 +1,6 @@
+**Table of Contents -- TOC**
+
+ * [introduction.man%|%doctools::toc::introduction] : DocTools - Tables of Contents
+ * [processing.man%|%Processing]
+ ** [structure.man%|%doctools::toc::structure] : doctoc serialization utilities
+ ** [parse.man%|%doctools::toc::parse] : Parsing text in doctoc format
diff --git a/tcllib/modules/doctools2toc/tests/data/ok/wiki/4_toc2 b/tcllib/modules/doctools2toc/tests/data/ok/wiki/4_toc2
new file mode 100644
index 0000000..95976c6
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/ok/wiki/4_toc2
@@ -0,0 +1,6 @@
+**Table of Contents -- TOC**
+
+ * [introduction.man%|%doctools::toc::introduction] : DocTools - Tables of Contents
+ * [processing.man%|%Processing]
+ ** [parse.man%|%doctools::toc::parse] : Parsing text in doctoc format
+ * [structure.man%|%doctools::toc::structure] : doctoc serialization utilities
diff --git a/tcllib/modules/doctools2toc/tests/data/unexpected_char b/tcllib/modules/doctools2toc/tests/data/unexpected_char
new file mode 100644
index 0000000..9420cbd
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/unexpected_char
@@ -0,0 +1,2 @@
+[bad syntax in include file
+2]
diff --git a/tcllib/modules/doctools2toc/tests/data/unexpected_eof b/tcllib/modules/doctools2toc/tests/data/unexpected_eof
new file mode 100644
index 0000000..b56316c
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/data/unexpected_eof
@@ -0,0 +1 @@
+[bad syntax in include file \ No newline at end of file
diff --git a/tcllib/modules/doctools2toc/tests/export b/tcllib/modules/doctools2toc/tests/export
new file mode 100644
index 0000000..fee8c83
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/export
@@ -0,0 +1,147 @@
+# -*- tcl -*-
+# toc_export.testsuite: Tests for the management of toc export plugins.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: export,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+# Tests are run for all formats we have an export plugin for.
+
+# -------------------------------------------------------------------------
+
+set mytestdir tests/data
+set mytestconfig {fox dog lazy jump}
+set mytestincludes [TestFilesGlob $mytestdir]
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# doctoc markup
+
+# Testing the export of doctoc markup through an exporter manager, for
+# all possible configurations.
+
+foreach {k nl in al section} {
+ 0 0 0 0 -ultracompact
+ 1 1 0 0 -compact
+ 2 1 1 0 -indented
+ 3 1 0 1 -aligned
+ 4 1 1 1 -indalign
+ 5 0 1 0 -indented
+ 6 0 0 1 -aligned
+ 7 0 1 1 -indalign
+} {
+ TestFilesProcess $mytestdir ok serial doctoc$section -> n label input data expected {
+ test doctools-toc-export-plugin-doctoc-20.$k.$n "doctools::toc::export /doctoc, $label$section, ok" -setup {
+ doctools::toc::export OUT
+ OUT config set newlines $nl
+ OUT config set indented $in
+ OUT config set aligned $al
+ } -body {
+ stripcomments [OUT export serial $data doctoc]
+ } -cleanup {
+ OUT destroy
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# text markup
+
+TestFilesProcess $mytestdir ok serial text -> n label input data expected {
+ test doctools-toc-export-plugin-text-21.$n "doctools::toc::export /text, $label, ok" -setup {
+ doctools::toc::export OUT
+ } -body {
+ OUT export serial $data text
+ } -cleanup {
+ OUT destroy
+ } -result $expected
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# json markup
+
+foreach {k in al section} {
+ 0 0 0 -ultracompact
+ 1 1 0 -indented
+ 2 0 1 -indalign
+ 3 1 1 -indalign
+} {
+ TestFilesProcess $mytestdir ok serial json$section -> n label input data expected {
+ test doctools-toc-export-plugin-json-22.$k.$n "doctools::toc::export /json, $label$section, ok" -setup {
+ doctools::toc::export OUT
+ OUT config set indented $in
+ OUT config set aligned $al
+ } -body {
+ OUT export serial $data json
+ } -cleanup {
+ OUT destroy
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# html markup
+
+foreach {k nl in section} {
+ 0 0 0 -ultracompact
+ 1 0 1 -indented
+ 2 1 0 -compact
+ 3 1 1 -indented
+} {
+ TestFilesProcess $mytestdir ok serial html$section -> n label input data expected {
+ test doctools-toc-export-plugin-html-23.$k.$n "doctools::toc::export /html, $label$section, ok" -setup {
+ doctools::toc::export OUT
+ OUT config set newlines $nl
+ OUT config set indented $in
+ OUT config set user _dummy_
+ } -body {
+ striphtmlcomments [OUT export serial $data html] 3
+ } -cleanup {
+ OUT destroy
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# wiki markup
+
+TestFilesProcess $mytestdir ok serial wiki -> n label input data expected {
+ test doctools-toc-export-plugin-wiki-23.$n "doctools::toc::export /wiki, $label, ok" -setup {
+ doctools::toc::export OUT
+ } -body {
+ OUT export serial $data wiki
+ } -cleanup {
+ OUT destroy
+ } -result $expected
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# nroff markup
+
+foreach {k inline section} {
+ 0 0 -external
+ 1 1 -inlined
+} {
+ TestFilesProcess $mytestdir ok serial nroff$section -> n label input data expected {
+ test doctools-toc-export-plugin-nroff-24.$k.$n "doctools::toc::export /nroff, $label$section, ok" -setup {
+ doctools::toc::export OUT
+ OUT config set inline $inline
+ } -body {
+ stripnroffcomments [stripmanmacros [OUT export serial $data nroff]]
+ } -cleanup {
+ OUT destroy
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+unset mytestdir n label input data expected
+return
diff --git a/tcllib/modules/doctools2toc/tests/export_doctoc b/tcllib/modules/doctools2toc/tests/export_doctoc
new file mode 100644
index 0000000..aab471b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/export_doctoc
@@ -0,0 +1,5 @@
+# -*- tcl -*-
+# This file is not required as the .test file already does all the
+# tests without the need for an additional sourced control file.
+# We have it here just as a reminder.
+return
diff --git a/tcllib/modules/doctools2toc/tests/export_text b/tcllib/modules/doctools2toc/tests/export_text
new file mode 100644
index 0000000..aab471b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/export_text
@@ -0,0 +1,5 @@
+# -*- tcl -*-
+# This file is not required as the .test file already does all the
+# tests without the need for an additional sourced control file.
+# We have it here just as a reminder.
+return
diff --git a/tcllib/modules/doctools2toc/tests/import b/tcllib/modules/doctools2toc/tests/import
new file mode 100644
index 0000000..feacfac
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/import
@@ -0,0 +1,174 @@
+# -*- tcl -*-
+# toc_import.testsuite: Tests for the management of toc import plugins.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: import,v 1.2 2009/11/15 05:50:03 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+# Tests are run for all formats we have an import plugin for.
+
+# -------------------------------------------------------------------------
+
+set mytestdir tests/data
+set mytestconfig {fox dog lazy jump}
+set mytestincludes [TestFilesGlob $mytestdir]
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# doctoc markup
+
+# We are checking that the various forms of doctoc markup, as can be
+# generated by doctools::toc(::format::doctoc) are valid input to the
+# doctoc parser.
+
+foreach {k section} {
+ 0 {}
+ 1 -ultracompact
+ 2 -compact
+ 3 -indented
+ 4 -aligned
+ 5 -indalign
+} {
+ TestFilesProcess $mytestdir ok doctoc$section serial-print -> n label input data expected {
+ test doctools-toc-import-plugin-doctoc-20.$k.$n "doctools::toc::import text /doctoc, $label$section, ok" -setup {
+ doctools::toc::import I
+ foreach {n v} $mytestconfig { I config set $n $v }
+ foreach p $mytestincludes { I include add $p }
+ } -body {
+ doctools::toc::structure print [I import text $data doctoc]
+ } -cleanup {
+ I destroy
+ } -result $expected
+ }
+
+ TestFilesProcess $mytestdir ok doctoc$section serial-print -> n label input data expected {
+ test doctools-toc-import-plugin-doctoc-21.$k.$n "doctools::toc::import file /doctoc, $label$section, ok" -setup {
+ doctools::toc::import I
+ foreach {n v} $mytestconfig { I config set $n $v }
+ foreach p $mytestincludes { I include add $p }
+ } -body {
+ doctools::toc::structure print [I import file $input doctoc]
+ } -cleanup {
+ I destroy
+ } -result $expected
+ }
+}
+
+# We test the error messages and codes thrown by the parser for a
+# variety of failure possibilities.
+
+TestFilesProcess $mytestdir fail doctoc emsg -> n label input data expected {
+ test doctools-toc-import-plugin-doctoc-22.$n "doctools::toc::import text /doctoc, $label, error message" -setup {
+ doctools::toc::import I
+ foreach {n v} $mytestconfig { I config set $n $v }
+ foreach p $mytestincludes { I include add $p }
+ } -body {
+ I import text $data doctoc
+ } -cleanup {
+ I destroy
+ } -returnCodes error -result $expected
+}
+
+TestFilesProcess $mytestdir fail doctoc ecode -> n label input data expected {
+ test doctools-toc-import-plugin-doctoc-23.$n "doctools::toc::import text /doctoc, $label, error code" -setup {
+ doctools::toc::import I
+ foreach {n v} $mytestconfig { I config set $n $v }
+ foreach p $mytestincludes { I include add $p }
+ } -body {
+ # Catch and rethrow using the error code as new message.
+ catch { I import text $data doctoc }
+ set ::errorCode
+ } -cleanup {
+ I destroy
+ } -result $expected
+}
+
+TestFilesProcess $mytestdir fail doctoc emsg -> n label input data expected {
+ test doctools-toc-import-plugin-doctoc-24.$n "doctools::toc::import file /doctoc, $label, error message" -setup {
+ doctools::toc::import I
+ foreach {n v} $mytestconfig { I config set $n $v }
+ foreach p $mytestincludes { I include add $p }
+ } -body {
+ I import file $input doctoc
+ } -cleanup {
+ I destroy
+ } -returnCodes error -result $expected
+}
+
+TestFilesProcess $mytestdir fail doctoc ecode -> n label input data expected {
+ test doctools-toc-import-plugin-doctoc-25.$n "doctools::toc::import file /doctoc, $label, error code" -setup {
+ doctools::toc::import I
+ foreach {n v} $mytestconfig { I config set $n $v }
+ foreach p $mytestincludes { I include add $p }
+ } -body {
+ # Catch and rethrow using the error code as new message.
+ catch { I import file $input doctoc }
+ set ::errorCode
+ } -cleanup {
+ I destroy
+ } -result $expected
+}
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# text markup - This is not an importable format.
+
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+# json - Java Script Object Notation
+
+# We are checking that the various forms of json markup, as can be
+# generated by doctools::toc(::export(::json)) are valid input to the
+# json parser.
+#
+# section {} holds the non-canonical input we have to accept and make
+# canonical to higher layers.
+
+foreach {k section} {
+ 0 {}
+ 1 -ultracompact
+ 2 -indented
+ 3 -indalign
+} {
+ TestFilesProcess $mytestdir ok json$section serial-print -> n label input data expected {
+ test doctools-toc-import-plugin-json-26.$k.$n "doctools::toc::import text /json, $label$section, ok" -setup {
+ doctools::toc::import I
+ } -body {
+ doctools::toc::structure print [I import text $data json]
+ } -cleanup {
+ I destroy
+ } -result $expected
+ }
+
+ TestFilesProcess $mytestdir ok json$section serial-print -> n label input data expected {
+ test doctools-toc-import-plugin-json-27.$k.$n "doctools::toc::import file /json, $label$section, ok" -setup {
+ doctools::toc::import I
+ } -body {
+ doctools::toc::structure print [I import file $input json]
+ } -cleanup {
+ I destroy
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+
+# We test the error messages and codes thrown by the parser for a
+# variety of failure possibilities.
+
+TestFilesProcess $mytestdir fail json json-emsg -> n label input data expected {
+ test doctools-toc-import-plugin-json-28.$n "doctools::toc::import text /json, $label, error message" -setup {
+ doctools::toc::import I
+ } -body {
+ I import text $data json
+ } -cleanup {
+ I destroy
+ } -returnCodes error -result $expected
+}
+
+# -------------------------------------------------------------------------
+unset mytestdir n label input data expected
+return
diff --git a/tcllib/modules/doctools2toc/tests/import_doctoc b/tcllib/modules/doctools2toc/tests/import_doctoc
new file mode 100644
index 0000000..056ca67
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/import_doctoc
@@ -0,0 +1,73 @@
+# -*- tcl -*-
+# toc_import_doctoc.testsuite: tests for the doctoc import plugin.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: import_doctoc,v 1.1 2009/04/18 21:14:21 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+set mytestconfig {fox dog lazy jump}
+set mytestincludes [TestFilesGlob $mytestdir]
+
+# -------------------------------------------------------------------------
+
+# We are checking that the various forms of doctoc markup, as can be
+# generated by doctools::toc(::export(::doctoc)) are valid input to
+# the doctoc parser.
+#
+# section {} holds the non-canonical input we have to accept and make
+# canonical to higher layers.
+
+foreach {k section} {
+ 0 {}
+ 1 -ultracompact
+ 2 -compact
+ 3 -indented
+ 4 -aligned
+ 5 -indalign
+} {
+ TestFilesProcess $mytestdir ok doctoc$section serial-print -> n label input data expected {
+ test doctools-toc-import-doctoc-${stkimpl}-${setimpl}-${impl}-2.$k.$n "doctools::toc::import::doctoc, $label$section, ok" -setup {
+ doctools::toc::parse include set $mytestincludes
+ } -body {
+ doctools::toc::structure print [import $data $mytestconfig]
+ } -cleanup {
+ doctools::toc::parse include clear
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+
+# We test the error messages and codes thrown by the parser for a
+# variety of failure possibilities.
+
+TestFilesProcess $mytestdir fail doctoc emsg -> n label input data expected {
+ test doctools-toc-import-doctoc-${stkimpl}-${setimpl}-${impl}-3.$n "doctools::toc::import::doctoc, $label, error message" -setup {
+ doctools::toc::parse include set $mytestincludes
+ } -body {
+ import $data $mytestconfig
+ } -cleanup {
+ doctools::toc::parse include clear
+ } -returnCodes error -result $expected
+}
+
+TestFilesProcess $mytestdir fail doctoc ecode -> n label input data expected {
+ test doctools-toc-import-doctoc-${stkimpl}-${setimpl}-${impl}-4.$n "doctools::toc::import::doctoc, $label, error code" -setup {
+ doctools::toc::parse include set $mytestincludes
+ } -body {
+ # Catch and rethrow using the error code as new message.
+ catch { import $data $mytestconfig }
+ set ::errorCode
+ } -cleanup {
+ doctools::toc::parse include clear
+ } -result $expected
+}
+
+# -------------------------------------------------------------------------
+unset mytestdir n label input data expected
+return
diff --git a/tcllib/modules/doctools2toc/tests/parse b/tcllib/modules/doctools2toc/tests/parse
new file mode 100644
index 0000000..70f4007
--- /dev/null
+++ b/tcllib/modules/doctools2toc/tests/parse
@@ -0,0 +1,130 @@
+# -*- tcl -*-
+# doctoc_parse.testsuite: tests for the doctoc parser.
+#
+# Copyright (c) 2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: parse,v 1.1 2009/04/18 21:14:21 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [tcllibPath doctools2base/tests/common]
+set mytestdir tests/data
+
+# -------------------------------------------------------------------------
+
+# We are checking that the various forms of doctoc markup, as can be
+# generated by doctools::toc::export::doctoc are valid input to the
+# doctoc parser.
+#
+# section {} holds the non-canonical input we have to accept and make
+# canonical to higher layers.
+
+foreach {k section} {
+ 0 {}
+ 1 -ultracompact
+ 2 -compact
+ 3 -indented
+ 4 -aligned
+ 5 -indalign
+} {
+ TestFilesProcess $mytestdir ok doctoc$section serial-print -> n label input data expected {
+ test doctools-toc-parse-${stkimpl}-${setimpl}-${impl}-20.$k.$n "doctools::toc::parse text, $label$section, ok" -setup {
+ # Define a few basic variables and include search paths for
+ # use by the test
+ doctools::toc::parse var load {fox dog lazy jump}
+ doctools::toc::parse include set [TestFilesGlob $mytestdir]
+ } -body {
+ doctools::toc::structure print \
+ [doctools::toc::parse text $data]
+ } -cleanup {
+ doctools::toc::parse include clear
+ doctools::toc::parse var unset *
+ } -result $expected
+ }
+
+ TestFilesProcess $mytestdir ok doctoc$section serial-print -> n label input data expected {
+ test doctools-toc-parse-${stkimpl}-${setimpl}-${impl}-21.$k.$n "doctools::toc::parse file, $label$section, ok" -setup {
+ # Define a few basic variables and include search paths for
+ # use by the test
+ doctools::toc::parse var load {fox dog lazy jump}
+ doctools::toc::parse include set [TestFilesGlob $mytestdir]
+ } -body {
+ doctools::toc::structure print \
+ [doctools::toc::parse file $input]
+ } -cleanup {
+ doctools::toc::parse include clear
+ doctools::toc::parse var unset *
+ } -result $expected
+ }
+}
+
+# -------------------------------------------------------------------------
+
+# We test the error messages and codes thrown by the parser for a
+# variety of failure possibilities.
+
+TestFilesProcess $mytestdir fail doctoc emsg -> n label input data expected {
+ test doctools-toc-parse-${stkimpl}-${setimpl}-${impl}-22.$n "doctools::toc::parse, $label, error message" -setup {
+ # Define a few basic variables and include search paths for
+ # use by the test
+ doctools::toc::parse var load {fox dog lazy jump}
+ doctools::toc::parse include set [TestFilesGlob $mytestdir]
+ } -body {
+ doctools::toc::parse text $data
+ } -cleanup {
+ doctools::toc::parse include clear
+ doctools::toc::parse var unset *
+ } -returnCodes error -result $expected
+}
+
+TestFilesProcess $mytestdir fail doctoc ecode -> n label input data expected {
+ test doctools-toc-parse-${stkimpl}-${setimpl}-${impl}-23.$n "doctools::toc::parse, $label, error code" -setup {
+ # Define a few basic variables and include search paths for
+ # use by the test
+ doctools::toc::parse var load {fox dog lazy jump}
+ doctools::toc::parse include set [TestFilesGlob $mytestdir]
+ } -body {
+ # Catch and rethrow using the error code as new message.
+ catch { doctools::toc::parse text $data }
+ set ::errorCode
+ } -cleanup {
+ doctools::toc::parse include clear
+ doctools::toc::parse var unset *
+ } -result $expected
+}
+
+TestFilesProcess $mytestdir fail doctoc emsg -> n label input data expected {
+ test doctools-toc-parse-${stkimpl}-${setimpl}-${impl}-24.$n "doctools::toc::parse file, $label, error message" -setup {
+ # Define a few basic variables and include search paths for
+ # use by the test
+ doctools::toc::parse var load {fox dog lazy jump}
+ doctools::toc::parse include set [TestFilesGlob $mytestdir]
+ } -body {
+ catch { [doctools::toc::parse file $input] } msg
+ string map [list "\"$input\" " {}] $msg
+ } -cleanup {
+ doctools::toc::parse include clear
+ doctools::toc::parse var unset *
+ } -result $expected
+}
+
+TestFilesProcess $mytestdir fail doctoc ecode -> n label input data expected {
+ test doctools-toc-parse-${stkimpl}-${setimpl}-${impl}-25.$n "doctools::toc::parse file, $label, error code" -setup {
+ # Define a few basic variables and include search paths for
+ # use by the test
+ doctools::toc::parse var load {fox dog lazy jump}
+ doctools::toc::parse include set [TestFilesGlob $mytestdir]
+ } -body {
+ # Catch and rethrow using the error code as new message.
+ catch { doctools::toc::parse file $input }
+ string map [list $input {{}}] $::errorCode
+ } -cleanup {
+ doctools::toc::parse include clear
+ doctools::toc::parse var unset *
+ } -result $expected
+}
+
+# -------------------------------------------------------------------------
+unset mytestdir n label input data expected
+return
diff --git a/tcllib/modules/doctools2toc/toc_container.man b/tcllib/modules/doctools2toc/toc_container.man
new file mode 100644
index 0000000..1cfe961
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_container.man
@@ -0,0 +1,370 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin doctools::toc n 2]
+[keywords conversion]
+[keywords {doctoc markup}]
+[keywords documentation]
+[keywords formatting]
+[keywords generation]
+[keywords HTML]
+[keywords json]
+[keywords latex]
+[keywords markup]
+[keywords nroff]
+[keywords parsing]
+[keywords plugin]
+[keywords reference]
+[keywords table]
+[keywords {table of contents}]
+[keywords {tcler's wiki}]
+[keywords text]
+[keywords TMML]
+[keywords wiki]
+[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Documentation tools}]
+[titledesc {Holding tables of contents}]
+[category {Documentation tools}]
+[require doctools::toc [opt 2]]
+[require Tcl 8.4]
+[require doctools::toc::structure]
+[require struct::tree]
+[require snit]
+[description]
+
+This package provides a class to contain and programmatically
+manipulate tables of contents.
+
+[para]
+
+This is one of the three public pillars the management of tables of
+contents resides on. The other two pillars are
+
+[list_begin enum]
+[enum] [manpage {Exporting tables of contents}], and
+[enum] [manpage {Importing tables of contents}]
+[list_end]
+
+[para]
+
+For information about the [sectref Concepts] of tables of contents, and
+their parts, see the same-named section.
+
+For information about the data structure which is used to encode
+tables of contents as values see the section
+[sectref {ToC serialization format}].
+
+This is the only format directly known to this class. Conversions from
+and to any other format are handled by export and import manager
+objects. These may be attached to a container, but do not have to be,
+it is merely a convenience.
+
+[section Concepts] [include include/concept.inc]
+
+[section API]
+[subsection {Package commands}]
+
+[list_begin definitions]
+
+[call [cmd ::doctools::toc] [arg objectName]]
+
+This command creates a new container object with an associated Tcl
+command whose name is [arg objectName]. This [term object] command is
+explained in full detail in the sections [sectref {Object command}]
+and [sectref {Object methods}]. The object command will be created
+under the current namespace if the [arg objectName] is not fully
+qualified, and in the specified namespace otherwise.
+
+[list_end]
+
+[subsection {Object command}]
+
+All objects created by the [cmd ::doctools::toc] command have the
+following general form:
+
+[list_begin definitions]
+
+[call [cmd objectName] [method method] [opt [arg "arg arg ..."]]]
+
+The method [method method] and its [arg arg]'uments determine the
+exact behavior of the command.
+
+See section [sectref {Object methods}] for the detailed
+specifications.
+
+[list_end]
+
+[subsection {Object methods}]
+
+[list_begin definitions]
+
+[call [arg objectName] [method destroy]]
+
+This method destroys the object it is invoked for.
+
+[call [arg objectName] [method {+ reference}] [arg id] [arg label] [arg docid] [arg desc]]
+
+This method adds a new reference element to the table of contents,
+under the element specified via its handle [arg id]. This parent
+element has to be a division element, or the root. An error is thrown
+otherwise.
+
+The new element will be externally identified by its [arg label],
+which has to be be unique within the parent element. An error is
+thrown otherwise.
+
+[para]
+
+As a reference element it will refer to a document identified by the
+symbolic [arg docid]. This reference must not be the empty string, an
+error is thrown otherwise.
+
+Beyond the label the element also has a longer descriptive string,
+supplied via [arg desc].
+
+[para]
+
+The result of the method is the handle (id) of the new element.
+
+[call [arg objectName] [method {+ division}] [arg id] [arg label] [opt [arg docid]]]
+
+This method adds a new division element to the table of contents,
+under the element specified via its handle [arg id]. This parent
+element has to be a division element, or the root. An error is thrown
+otherwise.
+
+The new element will be externally identified by its [arg label],
+which has to be be unique within the parent element. An error is
+thrown otherwise.
+
+[para]
+
+As a division element it is can refer to a document, identified by the
+symbolic [arg docid], but may choose not to.
+
+[para]
+
+The result of the method is the handle (id) of the new element.
+
+[call [arg objectName] [method remove] [arg id]]
+
+This method removes the element identified by the handle [arg id] from
+the table of contents.
+
+If the element is a division all of its children, if any, are removed
+as well. The root element/division of the table of contents cannot be
+removed however, only its children.
+
+[para]
+
+The result of the method is the empty string.
+
+[call [arg objectName] [method up] [arg id]]
+
+This method returns the handle of the parent for the element
+identified by its handle [arg id], or the empty string if [arg id]
+refered to the root element.
+
+[call [arg objectName] [method next] [arg id]]
+
+This method returns the handle of the right sibling for the element
+identified by its handle [arg id], or the handle of the parent if the
+element has no right sibling, or the empty string if [arg id] refered
+to the root element.
+
+[call [arg objectName] [method prev] [arg id]]
+
+This method returns the handle of the left sibling for the element
+identified by its handle [arg id], or the handle of the parent if the
+element has no left sibling, or the empty string if [arg id] refered
+to the root element.
+
+[call [arg objectName] [method child] [arg id] [arg label] [opt [arg ...]]]
+
+This method returns the handle of a child of the element identified by
+its handle [arg id]. The child itself is identified by a series of
+labels.
+
+[call [arg objectName] [method element] [opt [arg ...]]]
+
+This method returns the handle of the element identified by a series
+of labels, starting from the root of the table of contents. The series
+of labels is allowed to be empty, in which case the handle of the root
+element is returned.
+
+[call [arg objectName] [method children] [arg id]]
+
+This method returns a list containing the handles of all children of
+the element identified by the handle [arg id], from first to last, in
+that order.
+
+[call [arg objectName] [method type] [arg id]]
+
+This method returns the type of the element, either [const reference],
+or [const division].
+
+[call [arg objectName] [method full-label] [arg id]]
+
+This method is the complement of the method [method element],
+converting the handle [arg id] of an element into a list of labels
+full identifying the element within the whole table of contents.
+
+[call [arg objectName] [method elabel] [arg id] [opt [arg newlabel]]]
+
+This method queries and/or changes the label of the element identified
+by the handle [arg id]. If the argument [arg newlabel] is present then
+the label is changed to that value. Regardless of this, the result of
+the method is the current value of the label.
+
+[para]
+
+If the label is changed the new label has to be unique within the
+containing division, or an error is thrown.
+
+[para]
+
+Further, of the [arg id] refers to the root element of the table of
+contents, then using this method is equivalent to using the method
+[arg label], i.e. it is accessing the global label for the whole
+table.
+
+[call [arg objectName] [method description] [arg id] [opt [arg newdesc]]]
+
+This method queries and/or changes the description of the element
+identified by the handle [arg id]. If the argument [arg newdesc] is
+present then the description is changed to that value. Regardless of
+this, the result of the method is the current value of the description.
+
+[para]
+
+The element this method operates on has to be a reference element, or
+an error will be thrown.
+
+[call [arg objectName] [method document] [arg id] [opt [arg newdocid]]]
+
+This method queries and/or changes the document reference of the
+element identified by the handle [arg id].
+
+If the argument [arg newdocid] is present then the description is
+changed to that value. Regardless of this, the result of the method is
+the current value of the document reference.
+
+[para]
+
+Setting the reference to the empty string means unsetting it, and is
+allowed only for division elements. Conversely, if the result is the
+empty string then the element has no document reference, and this can
+happen only for division elements.
+
+[call [arg objectName] [method title]]
+
+Returns the currently defined title of the table of contents.
+
+[call [arg objectName] [method title] [arg text]]
+
+Sets the title of the table of contents to [arg text], and returns it as
+the result of the command.
+
+[call [arg objectName] [method label]]
+
+Returns the currently defined label of the table of contents.
+
+[call [arg objectName] [method label] [arg text]]
+
+Sets the label of the table of contents to [arg text], and returns it as
+the result of the command.
+
+[call [arg objectName] [method importer]]
+
+Returns the import manager object currently attached to the container,
+if any.
+
+[call [arg objectName] [method importer] [arg object]]
+
+Attaches the [arg object] as import manager to the container, and
+returns it as the result of the command.
+
+Note that the [arg object] is [emph not] put into ownership of the
+container. I.e., destruction of the container will [emph not] destroy
+the [arg object].
+
+[para]
+
+It is expected that [arg object] provides a method named
+[method {import text}] which takes a text and a format name, and
+returns the canonical serialization of the table of contents contained in
+the text, assuming the given format.
+
+[call [arg objectName] [method exporter]]
+
+Returns the export manager object currently attached to the container,
+if any.
+
+[call [arg objectName] [method exporter] [arg object]]
+
+Attaches the [arg object] as export manager to the container, and
+returns it as the result of the command.
+
+Note that the [arg object] is [emph not] put into ownership of the
+container. I.e., destruction of the container will [emph not] destroy
+the [arg object].
+
+[para]
+
+It is expected that [arg object] provides a method named
+[method {export object}] which takes the container and a format name,
+and returns a text encoding table of contents stored in the container, in
+the given format. It is further expected that the [arg object] will
+use the container's method [method serialize] to obtain the
+serialization of the table of contents from which to generate the text.
+
+[call [arg objectName] [method {deserialize =}] [arg data] [opt [arg format]]]
+
+This method replaces the contents of the table object with the table
+contained in the [arg data]. If no [arg format] was specified it is
+assumed to be the regular serialization of a table of contents.
+
+[para]
+
+Otherwise the object will use the attached import manager to convert
+the data from the specified format to a serialization it can handle.
+
+In that case an error will be thrown if the container has no import
+manager attached to it.
+
+[para]
+
+The result of the method is the empty string.
+
+[call [arg objectName] [method {deserialize +=}] [arg data] [opt [arg format]]]
+
+This method behaves like [method {deserialize =}] in its essentials,
+except that it merges the table of contents in the [arg data] to its
+contents instead of replacing it.
+
+The method will throw an error if merging is not possible, i.e. would
+produce an invalid table. The existing content is left unchanged in
+that case.
+
+[para]
+
+The result of the method is the empty string.
+
+[call [arg objectName] [method serialize] [opt [arg format]]]
+
+This method returns the table of contents contained in the object. If no
+[arg format] is not specified the returned result is the canonical
+serialization of its contents.
+
+[para]
+
+Otherwise the object will use the attached export manager to convert
+the data to the specified format.
+
+In that case an error will be thrown if the container has no export
+manager attached to it.
+
+[list_end]
+
+[include include/serialization.inc]
+[vset CATEGORY doctools]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/doctools2toc/toc_export.man b/tcllib/modules/doctools2toc/toc_export.man
new file mode 100644
index 0000000..91a87e7
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_export.man
@@ -0,0 +1,306 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin doctools::toc::export n 0.1]
+[keywords conversion]
+[keywords doctoc]
+[keywords documentation]
+[keywords export]
+[keywords formatting]
+[keywords generation]
+[keywords HTML]
+[keywords json]
+[keywords manpage]
+[keywords markup]
+[keywords nroff]
+[keywords plugin]
+[keywords reference]
+[keywords table]
+[keywords {table of contents}]
+[keywords {tcler's wiki}]
+[keywords text]
+[keywords url]
+[keywords wiki]
+[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Documentation tools}]
+[titledesc {Exporting tables of contents}]
+[category {Documentation tools}]
+[require doctools::toc::export [opt 0.1]]
+[require Tcl 8.4]
+[require doctools::config]
+[require doctools::toc::structure]
+[require snit]
+[require pluginmgr]
+[description]
+
+This package provides a class to manage the plugins for the export of
+tables of contents to other formats, i.e. their conversion to, for
+example [term doctoc], [term HTML], etc.
+
+[para]
+
+This is one of the three public pillars the management of tables of
+contents resides on. The other two pillars are
+
+[list_begin enum]
+[enum] [manpage {Importing tables of contents}], and
+[enum] [manpage {Holding tables of contents}]
+[list_end]
+
+[para]
+
+For information about the [sectref Concepts] of tables of contents,
+and their parts, see the same-named section.
+
+For information about the data structure which is the major input to
+the manager objects provided by this package see the section
+[sectref {ToC serialization format}].
+
+[para]
+
+The plugin system of our class is based on the package
+[package pluginmgr], and configured to look for plugins using
+
+[list_begin enum]
+[enum] the environment variable [var DOCTOOLS_TOC_EXPORT_PLUGINS],
+[enum] the environment variable [var DOCTOOLS_TOC_PLUGINS],
+[enum] the environment variable [var DOCTOOLS_PLUGINS],
+[enum] the path [file {~/.doctools/toc/export/plugin}]
+[enum] the path [file {~/.doctools/toc/plugin}]
+[enum] the path [file {~/.doctools/plugin}]
+[enum] the path [file {~/.doctools/toc/export/plugins}]
+[enum] the path [file {~/.doctools/toc/plugins}]
+[enum] the path [file {~/.doctools/plugins}]
+[enum] the registry entry "HKEY_CURRENT_USER\SOFTWARE\DOCTOOLS\TOC\EXPORT\PLUGINS"
+[enum] the registry entry "HKEY_CURRENT_USER\SOFTWARE\DOCTOOLS\TOC\PLUGINS"
+[enum] the registry entry "HKEY_CURRENT_USER\SOFTWARE\DOCTOOLS\PLUGINS"
+[list_end]
+
+The last three are used only when the package is run on a machine
+using Windows(tm) operating system.
+
+[para]
+
+The whole system is delivered with six predefined export plugins,
+namely
+
+[list_begin definitions]
+[def doctoc] See [manpage {doctoc export plugin}] for details.
+[def html] See [manpage {html export plugin}] for details.
+[def json] See [manpage {json export plugin}] for details.
+[def nroff] See [manpage {nroff export plugin}] for details.
+[def text] See [manpage {text export plugin}] for details.
+[def wiki] See [manpage {wiki export plugin}] for details.
+[list_end]
+
+[para]
+
+Readers wishing to write their own export plugin for some format, i.e.
+[term {plugin writer}]s reading and understanding the section
+containing the [sectref {Export plugin API v2 reference}] is an
+absolute necessity, as it specifies the interaction between this
+package and its plugins in detail.
+
+[section Concepts] [include include/concept.inc]
+
+[section API]
+[subsection {Package commands}]
+
+[list_begin definitions]
+
+[call [cmd ::doctools::toc::export] [arg objectName]]
+
+This command creates a new export manager object with an associated
+Tcl command whose name is [arg objectName]. This [term object] command
+is explained in full detail in the sections [sectref {Object command}]
+and [sectref {Object methods}]. The object command will be created
+under the current namespace if the [arg objectName] is not fully
+qualified, and in the specified namespace otherwise.
+
+[list_end]
+
+[subsection {Object command}]
+
+All objects created by the [cmd ::doctools::toc::export] command have
+the following general form:
+
+[list_begin definitions]
+
+[call [cmd objectName] [method method] [opt [arg "arg arg ..."]]]
+
+The method [method method] and its [arg arg]'uments determine the
+exact behavior of the command.
+
+See section [sectref {Object methods}] for the detailed
+specifications.
+
+[list_end]
+
+[subsection {Object methods}]
+
+[list_begin definitions]
+
+[call [arg objectName] [method destroy]]
+
+This method destroys the object it is invoked for.
+
+[call [arg objectName] [method {export serial}] [arg serial] [opt [arg format]]]
+
+This method takes the canonical serialization of a table of contents
+stored in [arg serial] and converts it to the specified [arg format],
+using the export plugin for the format. An error is thrown if no
+plugin could be found for the format.
+
+The string generated by the conversion process is returned as
+the result of this method.
+
+[para]
+
+If no format is specified the method defaults to [const doctoc].
+
+[para]
+
+The specification of what a [term canonical] serialization is can be
+found in the section [sectref {ToC serialization format}].
+
+[para]
+
+The plugin has to conform to the interface specified in section
+[sectref {Export plugin API v2 reference}].
+
+[call [arg objectName] [method {export object}] [arg object] [opt [arg format]]]
+
+This method is a convenient wrapper around the [method {export serial}]
+method described by the previous item.
+
+It expects that [arg object] is an object command supporting a
+[method serialize] method returning the canonical serialization of a
+table of contents. It invokes that method, feeds the result into
+[method {export serial}] and returns the resulting string as its own
+result.
+
+[call [arg objectName] [method {config names}]]
+
+This method returns a list containing the names of all configuration
+variables currently known to the object.
+
+[call [arg objectName] [method {config get}]]
+
+This method returns a dictionary containing the names and values of
+all configuration variables currently known to the object.
+
+[call [arg objectName] [method {config set}] [arg name] [opt [arg value]]]
+
+This method sets the configuration variable [arg name] to the
+specified [arg value] and returns the new value of the variable.
+
+[para]
+
+If no value is specified it simply returns the current value, without
+changing it.
+
+[para]
+
+Note that while the user can set the predefined configuration
+variables [const user] and [const format] doing so will have no
+effect, these values will be internally overriden when invoking an
+import plugin.
+
+[call [arg objectName] [method {config unset}] [arg pattern]...]
+
+This method unsets all configuration variables matching the specified
+glob [arg pattern]s. If no pattern is specified it will unset all
+currently defined configuration variables.
+
+[list_end]
+
+[section {Export plugin API v2 reference}]
+
+Plugins are what this package uses to manage the support for any
+output format beyond the [sectref {ToC serialization format}]. Here we
+specify the API the objects created by this package use to interact
+with their plugins.
+
+[para]
+
+A plugin for this package has to follow the rules listed below:
+
+[list_begin enumerated]
+
+[enum] A plugin is a package.
+
+[enum] The name of a plugin package has the form
+
+ doctools::toc::export::[var FOO],
+
+ where [var FOO] is the name of the format the plugin will
+ generate output for. This name is also the argument to provide
+ to the various [method export] methods of export manager
+ objects to get a string encoding a table of contents in that
+ format.
+
+[enum] The plugin can expect that the package
+ [package doctools::toc::export::plugin] is present, as
+ indicator that it was invoked from a genuine plugin manager.
+
+[enum] A plugin has to provide one command, with the signature shown
+ below.
+
+[list_begin definitions]
+[call [cmd export] [arg serial] [arg configuration]]
+
+Whenever an export manager of [package doctools::toc] has to generate
+output for a table of contents it will invoke this command.
+
+[list_begin arguments]
+
+[arg_def string serial]
+
+This argument will contain the [term canonical] serialization of the
+table of contents for which to generate the output.
+
+The specification of what a [term canonical] serialization is can be
+found in the section [sectref {ToC serialization format}].
+
+[arg_def dictionary configuration]
+
+This argument will contain the current configuration to apply to the
+generation, as a dictionary mapping from variable names to values.
+
+[para]
+
+The following configuration variables have a predefined meaning all
+plugins have to obey, although they can ignore this information at
+their discretion. Any other other configuration variables recognized
+by a plugin will be described in the manpage for that plugin.
+
+[list_begin definitions]
+
+[def user] This variable is expected to contain the name of the user
+ owning the process invoking the plugin.
+
+[def format] This variable is expected to contain the name of the
+ format whose plugin is invoked.
+
+[def file] This variable, if defined by the user of the table object
+ is expected to contain the name of the input file for which
+ the plugin is generating its output for.
+
+[def map] This variable, if defined by the user of the table object is
+ expected to contain a dictionary mapping from symbolic
+ document ids used in the table entries to actual paths (or
+ urls). A plugin has to be able to handle the possibility
+ that a document id is without entry in this mapping.
+
+[list_end][comment {-- predefined configuration variables --}]
+[list_end][comment {-- arguments --}]
+[list_end][comment {-- api command signatures --}]
+
+[enum] A single usage cycle of a plugin consists of the invokations of
+ the command [cmd export]. This call has to leave the plugin in
+ a state where another usage cycle can be run without problems.
+
+[list_end]
+
+[include include/serialization.inc]
+[vset CATEGORY doctools]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/doctools2toc/toc_export_html.man b/tcllib/modules/doctools2toc/toc_export_html.man
new file mode 100644
index 0000000..6124f48
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_export_html.man
@@ -0,0 +1,7 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE html]
+[vset NAME HTML]
+[vset REQUIRE html]
+[vset CONFIG html]
+[vset VERSION 0.1]
+[include include/export/plugin.inc]
diff --git a/tcllib/modules/doctools2toc/toc_export_json.man b/tcllib/modules/doctools2toc/toc_export_json.man
new file mode 100644
index 0000000..ce9e983
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_export_json.man
@@ -0,0 +1,7 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE json]
+[vset NAME JSON]
+[vset REQUIRE json]
+[vset CONFIG json]
+[vset VERSION 0.1]
+[include include/export/plugin.inc]
diff --git a/tcllib/modules/doctools2toc/toc_export_nroff.man b/tcllib/modules/doctools2toc/toc_export_nroff.man
new file mode 100644
index 0000000..cc17540
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_export_nroff.man
@@ -0,0 +1,7 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE nroff]
+[vset NAME nroff]
+[vset REQUIRE nroff]
+[vset CONFIG nroff]
+[vset VERSION 0.2]
+[include include/export/plugin.inc]
diff --git a/tcllib/modules/doctools2toc/toc_export_text.man b/tcllib/modules/doctools2toc/toc_export_text.man
new file mode 100644
index 0000000..6d718f8
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_export_text.man
@@ -0,0 +1,7 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE text]
+[vset NAME {plain text}]
+[vset REQUIRE text]
+[vset CONFIG text]
+[vset VERSION 0.1]
+[include include/export/plugin.inc]
diff --git a/tcllib/modules/doctools2toc/toc_export_wiki.man b/tcllib/modules/doctools2toc/toc_export_wiki.man
new file mode 100644
index 0000000..5a5eb1a
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_export_wiki.man
@@ -0,0 +1,7 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE wiki]
+[vset NAME wiki]
+[vset REQUIRE text]
+[vset CONFIG wiki]
+[vset VERSION 0.1]
+[include include/export/plugin.inc]
diff --git a/tcllib/modules/doctools2toc/toc_import.man b/tcllib/modules/doctools2toc/toc_import.man
new file mode 100644
index 0000000..e0edab0
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_import.man
@@ -0,0 +1,394 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin doctools::toc::import n 0.1]
+[keywords conversion]
+[keywords doctoc]
+[keywords documentation]
+[keywords import]
+[keywords json]
+[keywords manpage]
+[keywords markup]
+[keywords parsing]
+[keywords plugin]
+[keywords reference]
+[keywords table]
+[keywords {table of contents}]
+[keywords url]
+[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Documentation tools}]
+[titledesc {Importing keyword indices}]
+[category {Documentation tools}]
+[require doctools::toc::import [opt 0.1]]
+[require Tcl 8.4]
+[require doctools::config]
+[require doctools::toc::structure]
+[require snit]
+[require pluginmgr]
+[description]
+
+This package provides a class to manage the plugins for the import of
+tables of contents from other formats, i.e. their conversion from, for
+example [term doctoc], [term json], etc.
+
+[para]
+
+This is one of the three public pillars the management of tables of
+contents resides on. The other two pillars are
+
+[list_begin enum]
+[enum] [manpage {Exporting tables of contents}], and
+[enum] [manpage {Holding tables of contents}]
+[list_end]
+
+[para]
+
+For information about the [sectref Concepts] of tables of contents,
+and their parts, see the same-named section.
+
+For information about the data structure which is the major output of
+the manager objects provided by this package see the section
+[sectref {ToC serialization format}].
+
+[para]
+
+The plugin system of our class is based on the package
+[package pluginmgr], and configured to look for plugins using
+
+[list_begin enum]
+[enum] the environment variable [var DOCTOOLS_TOC_IMPORT_PLUGINS],
+[enum] the environment variable [var DOCTOOLS_TOC_PLUGINS],
+[enum] the environment variable [var DOCTOOLS_PLUGINS],
+[enum] the path [file {~/.doctools/toc/import/plugin}]
+[enum] the path [file {~/.doctools/toc/plugin}]
+[enum] the path [file {~/.doctools/plugin}]
+[enum] the path [file {~/.doctools/toc/import/plugins}]
+[enum] the path [file {~/.doctools/toc/plugins}]
+[enum] the path [file {~/.doctools/plugins}]
+[enum] the registry entry "HKEY_CURRENT_USER\SOFTWARE\DOCTOOLS\TOC\IMPORT\PLUGINS"
+[enum] the registry entry "HKEY_CURRENT_USER\SOFTWARE\DOCTOOLS\TOC\PLUGINS"
+[enum] the registry entry "HKEY_CURRENT_USER\SOFTWARE\DOCTOOLS\PLUGINS"
+[list_end]
+
+The last three are used only when the package is run on a machine
+using Windows(tm) operating system.
+
+[para]
+
+The whole system is delivered with two predefined import plugins,
+namely
+
+[list_begin definitions]
+[def doctoc] See [manpage {doctoc import plugin}] for details.
+[def json] See [manpage {json import plugin}] for details.
+[list_end]
+
+[para]
+
+Readers wishing to write their own import plugin for some format, i.e.
+[term {plugin writer}]s reading and understanding the section
+containing the [sectref {Import plugin API v2 reference}] is an
+absolute necessity, as it specifies the interaction between this
+package and its plugins in detail.
+
+[section Concepts] [include include/concept.inc]
+
+[section API]
+[subsection {Package commands}]
+
+[list_begin definitions]
+
+[call [cmd ::doctools::toc::import] [arg objectName]]
+
+This command creates a new import manager object with an associated
+Tcl command whose name is [arg objectName]. This [term object] command
+is explained in full detail in the sections [sectref {Object command}]
+and [sectref {Object methods}]. The object command will be created
+under the current namespace if the [arg objectName] is not fully
+qualified, and in the specified namespace otherwise.
+
+[list_end]
+
+[subsection {Object command}]
+
+All objects created by the [cmd ::doctools::toc::import] command have
+the following general form:
+
+[list_begin definitions]
+
+[call [cmd objectName] [method method] [opt [arg "arg arg ..."]]]
+
+The method [method method] and its [arg arg]'uments determine the
+exact behavior of the command.
+
+See section [sectref {Object methods}] for the detailed
+specifications.
+
+[list_end]
+
+[subsection {Object methods}]
+
+[list_begin definitions]
+
+[call [arg objectName] [method destroy]]
+
+This method destroys the object it is invoked for.
+
+[call [arg objectName] [method {import text}] [arg text] [opt [arg format]]]
+
+This method takes the [arg text] and converts it from the specified
+[arg format] to the canonical serialization of a table of contents using
+the import plugin for the format. An error is thrown if no plugin
+could be found for the format.
+
+The serialization generated by the conversion process is returned as
+the result of this method.
+
+[para]
+
+If no format is specified the method defaults to [const doctoc].
+
+[para]
+
+The specification of what a [term canonical] serialization is can be
+found in the section [sectref {ToC serialization format}].
+
+[para]
+
+The plugin has to conform to the interface specified in section
+[sectref {Import plugin API v2 reference}].
+
+[call [arg objectName] [method {import file}] [arg path] [opt [arg format]]]
+
+This method is a convenient wrapper around the [method {import text}]
+method described by the previous item.
+
+It reads the contents of the specified file into memory, feeds the
+result into [method {import text}] and returns the resulting
+serialization as its own result.
+
+[call [arg objectName] [method {import object text}] [arg object] \
+ [arg text] [opt [arg format]]]
+
+This method is a convenient wrapper around the [method {import text}]
+method described by the previous item.
+
+It expects that [arg object] is an object command supporting a
+[method deserialize] method expecting the canonical serialization of a
+table of contents.
+
+It imports the text using [method {import text}] and then feeds the
+resulting serialization into the [arg object] via [method deserialize].
+
+This method returns the empty string as it result.
+
+[call [arg objectName] [method {import object file}] [arg object] \
+ [arg path] [opt [arg format]]]
+
+This method behaves like [method {import object text}], except that it
+reads the text to convert from the specified file instead of being
+given it as argument.
+
+[call [arg objectName] [method {config names}]]
+
+This method returns a list containing the names of all configuration
+variables currently known to the object.
+
+[call [arg objectName] [method {config get}]]
+
+This method returns a dictionary containing the names and values of
+all configuration variables currently known to the object.
+
+[call [arg objectName] [method {config set}] [arg name] [opt [arg value]]]
+
+This method sets the configuration variable [arg name] to the
+specified [arg value] and returns the new value of the variable.
+
+[para]
+
+If no value is specified it simply returns the current value, without
+changing it.
+
+[para]
+
+Note that while the user can set the predefined configuration
+variables [const user] and [const format] doing so will have no
+effect, these values will be internally overriden when invoking an
+import plugin.
+
+[call [arg objectName] [method {config unset}] [arg pattern]...]
+
+This method unsets all configuration variables matching the specified
+glob [arg pattern]s. If no pattern is specified it will unset all
+currently defined configuration variables.
+
+[call [arg objectName] [method includes]]
+
+This method returns a list containing the currently specified paths to
+use to search for include files when processing input.
+
+The order of paths in the list corresponds to the order in which they
+are used, from first to last, and also corresponds to the order in
+which they were added to the object.
+
+[call [arg objectName] [method {include add}] [arg path]]
+
+This methods adds the specified [arg path] to the list of paths to use
+to search for include files when processing input. The path is added
+to the end of the list, causing it to be searched after all previously
+added paths. The result of the command is the empty string.
+
+[para]
+
+The method does nothing if the path is already known.
+
+[call [arg objectName] [method {include remove}] [arg path]]
+
+This methods removes the specified [arg path] from the list of paths
+to use to search for include files when processing input. The result
+of the command is the empty string.
+
+[para]
+
+The method does nothing if the path is not known.
+
+[call [arg objectName] [method {include clear}]]
+
+This method clears the list of paths to use to search for include
+files when processing input. The result of the command is the empty
+string.
+
+[list_end]
+
+[section {Import plugin API v2 reference}]
+
+Plugins are what this package uses to manage the support for any input
+format beyond the [sectref {ToC serialization format}]. Here we
+specify the API the objects created by this package use to interact
+with their plugins.
+
+[para]
+
+A plugin for this package has to follow the rules listed below:
+
+[list_begin enumerated]
+
+[enum] A plugin is a package.
+
+[enum] The name of a plugin package has the form
+
+ doctools::toc::import::[var FOO],
+
+ where [var FOO] is the name of the format the plugin will
+ generate output for. This name is also the argument to provide
+ to the various [method import] methods of import manager
+ objects to get a string encoding a table of contents in that
+ format.
+
+[enum] The plugin can expect that the package
+ [package doctools::toc::export::plugin] is present, as
+ indicator that it was invoked from a genuine plugin manager.
+
+[enum] The plugin can expect that a command named [cmd IncludeFile] is
+ present, with the signature
+
+[list_begin definitions]
+[call [cmd IncludeFile] [arg currentfile] [arg path]]
+
+This command has to be invoked by the plugin when it has to process an
+included file, if the format has the concept of such. An example of
+such a format would be [term doctoc].
+
+[para]
+The plugin has to supply the following arguments
+
+[list_begin arguments]
+[arg_def string currentfile]
+The path of the file it is currently processing. This may be the empty
+string if no such is known.
+
+[arg_def string path]
+The path of the include file as specified in the include directive
+being processed.
+
+[list_end]
+
+The result of the command will be a 5-element list containing
+
+[list_begin enum]
+
+[enum] A boolean flag indicating the success ([const True]) or failure
+ ([const False]) of the operation.
+
+[enum] In case of success the contents of the included file, and the
+ empty string otherwise.
+
+[enum] The resolved, i.e. absolute path of the included file, if
+ possible, or the unchanged [arg path] argument. This is for
+ display in an error message, or as the [arg currentfile]
+ argument of another call to [cmd IncludeFile] should this file
+ contain more files.
+
+[enum] In case of success an empty string, and for failure a code
+ indicating the reason for it, one of
+
+[list_begin definitions]
+[def notfound] The specified file could not be found.
+[def notread] The specified file was found, but not be read into memory.
+[list_end][comment {-- include error codes --}]
+
+[enum] An empty string in case of success of a [const notfound]
+ failure, and an additional error message describing the reason
+ for a [const notread] error in more detail.
+
+[list_end][comment {-- result list elements --}]
+[list_end][comment {-- include-file signature --}]
+
+[enum] A plugin has to provide one command, with the signature shown
+ below.
+
+[list_begin definitions]
+[call [cmd import] [arg text] [arg configuration]]
+
+Whenever an import manager of [package doctools::toc] has to parse
+input for a table of contents it will invoke this command.
+
+[list_begin arguments]
+
+[arg_def string text]
+
+This argument will contain the text encoding the table of contents per
+the format the plugin is for.
+
+[arg_def dictionary configuration]
+
+This argument will contain the current configuration to apply to the
+parsing, as a dictionary mapping from variable names to values.
+
+[para]
+
+The following configuration variables have a predefined meaning all
+plugins have to obey, although they can ignore this information at
+their discretion. Any other other configuration variables recognized
+by a plugin will be described in the manpage for that plugin.
+
+[list_begin definitions]
+
+[def user] This variable is expected to contain the name of the user
+ owning the process invoking the plugin.
+
+[def format] This variable is expected to contain the name of the
+ format whose plugin is invoked.
+
+[list_end][comment {-- predefined configuration variables --}]
+[list_end][comment {-- arguments --}]
+[list_end][comment {-- api command signatures --}]
+
+[enum] A single usage cycle of a plugin consists of the invokations of
+ the command [cmd import]. This call has to leave the plugin in
+ a state where another usage cycle can be run without problems.
+
+[list_end]
+
+[include include/serialization.inc]
+[vset CATEGORY doctools]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/doctools2toc/toc_import_json.man b/tcllib/modules/doctools2toc/toc_import_json.man
new file mode 100644
index 0000000..c097451
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_import_json.man
@@ -0,0 +1,6 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE json]
+[vset NAME JSON]
+[vset REQUIRE json]
+[vset CONFIG json]
+[include include/import/plugin.inc]
diff --git a/tcllib/modules/doctools2toc/toc_introduction.man b/tcllib/modules/doctools2toc/toc_introduction.man
new file mode 100644
index 0000000..78527db
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_introduction.man
@@ -0,0 +1,143 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin doctools2toc_introduction n 2.0]
+[see_also doctoc_intro]
+[see_also doctools]
+[see_also doctools2doc_introduction]
+[see_also doctools2idx_introduction]
+[see_also doctools_lang_cmdref]
+[see_also doctools_lang_faq]
+[see_also doctools_lang_intro]
+[see_also doctools_lang_syntax]
+[see_also doctools_plugin_apiref]
+[keywords contents]
+[keywords conversion]
+[keywords formatting]
+[keywords markup]
+[keywords parsing]
+[keywords plugin]
+[keywords {semantic markup}]
+[keywords {table of contents}]
+[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Documentation tools}]
+[titledesc {DocTools - Tables of Contents}]
+[category {Documentation tools}]
+[comment {
+}]
+[description]
+
+[term doctoc] (short for [emph {documentation tables of contents}])
+stands for a set of related, yet different, entities which are working
+together for the easy creation and transformation of tables and
+contents for documentation.
+
+[para]
+
+These are
+
+[list_begin enumerated]
+[enum]
+A tcl based language for the semantic markup of a table of contents.
+Markup is represented by Tcl commands.
+
+Beginners should start with the
+[manpage {doctoc language introduction}].
+
+The formal specification is split over two documents, one dealing with
+the [manpage {doctoc language syntax}], the other a
+[manpage {doctoc language command reference}].
+
+[enum]
+A set of packages for the programmatic manipulation of tables of
+contents in memory, and their conversion between various formats,
+reading and writing. The aforementioned markup language is one of the
+formats which can be both read from and written to.
+
+[enum]
+The system for the conversion of tables of contents is based on a
+plugin mechanism, for this we have two APIs describing the interface
+between the packages above and the import/export plugins.
+
+[list_end]
+
+[para]
+Which of the more detailed documents are relevant to the reader of
+this introduction depends on their role in the documentation process.
+
+[para]
+
+[list_begin enumerated]
+[enum]
+A [manpage writer] of documentation has to understand the markup language
+itself. A beginner to doctoc should read the more informally written
+[manpage {doctoc language introduction}] first. Having digested this
+the formal [manpage {doctoc language syntax}] specification should
+become understandable. A writer experienced with doctoc may only
+need the [manpage {doctoc language command reference}] from time to
+time to refresh her memory.
+
+[para]
+While a document is written the [syscmd dtp] application can be used
+to validate it, and after completion it also performs the conversion
+into the chosen system of visual markup, be it *roff, HTML, plain
+text, wiki, etc. The simpler [syscmd dtplite] application makes
+internal use of doctoc when handling directories of documentation,
+automatically generating a proper table of contents for them.
+
+[enum]
+A [term processor] of documentation written in the [term doctoc]
+markup language has to know which tools are available for use.
+
+[para]
+The main tool is the aforementioned [syscmd dtp] application provided
+by Tcllib. The simpler [syscmd dtplite] does not expose doctoc to the
+user. At the bottom level, common to both applications, however we
+find the three packages providing the basic facilities to handle
+tables of contents, i.e. import from textual formats, programmatic
+manipulation in memory, and export to textual formats. These are
+
+[list_begin definitions]
+[def [package doctoools::toc]]
+Programmatic manipulation of tables of contents in memory.
+
+[def [package doctoools::toc::import]]
+Import of tables of contents from various textual formats. The set of
+supported formats is extensible through plugin packages.
+
+[def [package doctoools::toc::export]]
+Export of tables of contents to various textual formats. The set of
+supported formats is extensible through plugin packages.
+
+[list_end]
+See also section [sectref {Package Overview}] for an overview of the
+dependencies between these and other, supporting packages.
+
+[enum]
+At last, but not least, [term {plugin writers}] have to understand the
+interaction between the import and export packages and their plugins.
+These APIs are described in the documentation for the two relevant
+packages, i.e.
+
+[list_begin itemized]
+[item] [package doctoools::toc::import]
+[item] [package doctoools::toc::export]
+[list_end]
+
+[list_end]
+
+[section {Related formats}]
+
+The doctoc format does not stand alone, it has two companion formats.
+These are called [term docidx] and [term doctools], and they are
+intended for the markup of [term {keyword indices}], and of general
+documentation, respectively.
+
+They are described in their own sets of documents, starting at
+the [manpage {DocTools - Keyword Indices}] and
+the [manpage {DocTools - General}], respectively.
+
+[section {Package Overview}]
+[include include/dependencies.inc]
+
+[vset CATEGORY doctools]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/doctools2toc/toc_msgcat_c.man b/tcllib/modules/doctools2toc/toc_msgcat_c.man
new file mode 100644
index 0000000..3bb3f54
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_msgcat_c.man
@@ -0,0 +1,5 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE c]
+[vset NAME C]
+[vset LONGNAME C]
+[include include/msgcat.inc]
diff --git a/tcllib/modules/doctools2toc/toc_msgcat_de.man b/tcllib/modules/doctools2toc/toc_msgcat_de.man
new file mode 100644
index 0000000..9c502a2
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_msgcat_de.man
@@ -0,0 +1,5 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE de]
+[vset NAME DE]
+[vset LONGNAME {DE (german)}]
+[include include/msgcat.inc]
diff --git a/tcllib/modules/doctools2toc/toc_msgcat_en.man b/tcllib/modules/doctools2toc/toc_msgcat_en.man
new file mode 100644
index 0000000..5dd9c3f
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_msgcat_en.man
@@ -0,0 +1,5 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE en]
+[vset NAME EN]
+[vset LONGNAME {EN (english)}]
+[include include/msgcat.inc]
diff --git a/tcllib/modules/doctools2toc/toc_msgcat_fr.man b/tcllib/modules/doctools2toc/toc_msgcat_fr.man
new file mode 100644
index 0000000..3e5229b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_msgcat_fr.man
@@ -0,0 +1,5 @@
+[comment {-*- tcl -*- --- doctools ---}]
+[vset PACKAGE fr]
+[vset NAME FR]
+[vset LONGNAME {FR (french)}]
+[include include/msgcat.inc]
diff --git a/tcllib/modules/doctools2toc/toc_parse.man b/tcllib/modules/doctools2toc/toc_parse.man
new file mode 100644
index 0000000..073581b
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_parse.man
@@ -0,0 +1,175 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin doctools::toc::parse n 1]
+[keywords doctoc]
+[keywords doctools]
+[keywords lexer]
+[keywords parser]
+[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Documentation tools}]
+[titledesc {Parsing text in doctoc format}]
+[category {Documentation tools}]
+[require doctools::toc::parse [opt 0.1]]
+[require Tcl 8.4]
+[require doctools::toc::structure]
+[require doctools::msgcat]
+[require doctools::tcl::parse]
+[require fileutil]
+[require logger]
+[require snit]
+[require struct::list]
+[require struct::stack]
+
+[description]
+
+This package provides commands to parse text written in the
+[term doctoc] markup language and convert it into the canonical
+serialization of the table of contents encoded in the text.
+
+See the section [sectref {ToC serialization format}] for specification
+of their format.
+
+[para]
+
+This is an internal package of doctools, for use by the higher level
+packages handling [term doctoc] documents.
+
+[section API]
+
+[list_begin definitions]
+
+[call [cmd ::doctools::toc::parse] [method text] [arg text]]
+
+The command takes the string contained in [arg text] and parses it
+under the assumption that it contains a document written using the
+[term doctoc] markup language. An error is thrown if this assumption
+is found to be false. The format of these errors is described in
+section [sectref {Parse errors}].
+
+[para]
+
+When successful the command returns the canonical serialization of the
+table of contents which was encoded in the text.
+
+See the section [sectref {ToC serialization format}] for specification
+of that format.
+
+[call [cmd ::doctools::toc::parse] [method file] [arg path]]
+
+The same as [method text], except that the text to parse is read from
+the file specified by [arg path].
+
+[call [cmd ::doctools::toc::parse] [method includes]]
+
+This method returns the current list of search paths used when looking
+for include files.
+
+[call [cmd ::doctools::toc::parse] [method {include add}] [arg path]]
+
+This method adds the [arg path] to the list of paths searched when
+looking for an include file. The call is ignored if the path is
+already in the list of paths. The method returns the empty string as
+its result.
+
+[call [cmd ::doctools::toc::parse] [method {include remove}] [arg path]]
+
+This method removes the [arg path] from the list of paths searched
+when looking for an include file. The call is ignored if the path is
+not contained in the list of paths. The method returns the empty
+string as its result.
+
+[call [cmd ::doctools::toc::parse] [method {include clear}]]
+
+This method clears the list of search paths for include files.
+
+[call [cmd ::doctools::toc::parse] [method vars]]
+
+This method returns a dictionary containing the current set of
+predefined variables known to the [cmd vset] markup command during
+processing.
+
+[call [cmd ::doctools::toc::parse] [method {var set}] [arg name] [arg value]]
+
+This method adds the variable [arg name] to the set of predefined
+variables known to the [cmd vset] markup command during processing,
+and gives it the specified [arg value]. The method returns the empty
+string as its result.
+
+[call [cmd ::doctools::toc::parse] [method {var unset}] [arg name]]
+
+This method removes the variable [arg name] from the set of predefined
+variables known to the [cmd vset] markup command during
+processing. The method returns the empty string as its result.
+
+[call [cmd ::doctools::toc::parse] [method {var clear}] [opt [arg pattern]]]
+
+This method removes all variables matching the [arg pattern] from the
+set of predefined variables known to the [cmd vset] markup command
+during processing. The method returns the empty string as its result.
+
+[para]
+
+The pattern matching is done with [cmd {string match}], and the
+default pattern used when none is specified, is [const *].
+
+[list_end]
+
+[section {Parse errors}]
+
+The format of the parse error messages thrown when encountering
+violations of the [term doctoc] markup syntax is human readable and
+not intended for processing by machines. As such it is not documented.
+
+[para]
+
+[emph However], the errorCode attached to the message is
+machine-readable and has the following format:
+
+[list_begin enumerated]
+[enum]
+The error code will be a list, each element describing a single error
+found in the input. The list has at least one element, possibly more.
+
+[enum]
+Each error element will be a list containing six strings describing an
+error in detail. The strings will be
+
+[list_begin enumerated]
+[enum]
+The path of the file the error occured in. This may be empty.
+
+[enum]
+The range of the token the error was found at. This range is a
+two-element list containing the offset of the first and last character
+in the range, counted from the beginning of the input (file). Offsets
+are counted from zero.
+
+[enum]
+The line the first character after the error is on.
+Lines are counted from one.
+
+[enum]
+The column the first character after the error is at.
+Columns are counted from zero.
+
+[enum]
+The message code of the error. This value can be used as argument to
+[cmd msgcat::mc] to obtain a localized error message, assuming that
+the application had a suitable call of [cmd doctools::msgcat::init] to
+initialize the necessary message catalogs (See package
+[package doctools::msgcat]).
+
+[enum]
+A list of details for the error, like the markup command involved. In
+the case of message code [const doctoc/include/syntax] this value is
+the set of errors found in the included file, using the format
+described here.
+
+[list_end]
+[list_end]
+
+[include include/format/doctoc.inc]
+[include include/serialization.inc]
+
+[vset CATEGORY doctools]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/doctools2toc/toc_structure.man b/tcllib/modules/doctools2toc/toc_structure.man
new file mode 100644
index 0000000..2e22128
--- /dev/null
+++ b/tcllib/modules/doctools2toc/toc_structure.man
@@ -0,0 +1,151 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin doctools::toc::structure n 0.1]
+[keywords deserialization]
+[keywords doctoc]
+[keywords doctools]
+[keywords serialization]
+[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Documentation tools}]
+[titledesc {Doctoc serialization utilities}]
+[category {Documentation tools}]
+[require doctools::toc::structure [opt 0.1]]
+[require Tcl 8.4]
+[require logger]
+[require snit]
+[description]
+
+This package provides commands to work with the serializations of
+tables of contents as managed by the doctools system v2, and specified
+in section [sectref {ToC serialization format}].
+
+[para]
+
+This is an internal package of doctools, for use by the higher level
+packages handling tables of contents and their conversion into and out
+of various other formats, like documents written using [term doctoc]
+markup.
+
+[section API]
+
+[list_begin definitions]
+
+[call [cmd ::doctools::toc::structure] [method verify] \
+ [arg serial] [opt [arg canonvar]]]
+
+This command verifies that the content of [arg serial] is a valid
+[term regular] serialization of a table of contents and will throw an
+error if that is not the case. The result of the command is the empty
+string.
+
+[para]
+
+If the argument [arg canonvar] is specified it is interpreted as the
+name of a variable in the calling context. This variable will be
+written to if and only if [arg serial] is a valid regular
+serialization. Its value will be a boolean, with [const True]
+indicating that the serialization is not only valid, but also
+[term canonical]. [const False] will be written for a valid, but
+non-canonical serialization.
+
+[para]
+
+For the specification of regular and canonical serializations see the
+section [sectref {ToC serialization format}].
+
+[call [cmd ::doctools::toc::structure] [method verify-as-canonical] \
+ [arg serial]]
+
+This command verifies that the content of [arg serial] is a valid
+[term canonical] serialization of a table of contents and will throw
+an error if that is not the case. The result of the command is the
+empty string.
+
+[para]
+
+For the specification of canonical serializations see the section
+[sectref {ToC serialization format}].
+
+[call [cmd ::doctools::toc::structure] [method canonicalize] [arg serial]]
+
+This command assumes that the content of [arg serial] is a valid
+[term regular] serialization of a table of contents and will throw an
+error if that is not the case.
+
+[para]
+
+It will then convert the input into the [term canonical] serialization
+of the contained table of contents and return it as its result. If the
+input is already canonical it will be returned unchanged.
+
+[para]
+
+For the specification of regular and canonical serializations see the
+section [sectref {ToC serialization format}].
+
+[call [cmd ::doctools::toc::structure] [method print] [arg serial]]
+
+This command assumes that the argument [arg serial] contains a valid
+regular serialization of a table of contents and returns a string
+containing that table in a human readable form.
+
+[para]
+
+The exact format of this form is not specified and cannot be relied on
+for parsing or other machine-based activities.
+
+[para]
+
+For the specification of regular serializations see the section
+[sectref {ToC serialization format}].
+
+[call [cmd ::doctools::toc::structure] [method merge] \
+ [arg seriala] [arg serialb]]
+
+This command accepts the regular serializations of two tables of
+contents and uses them to create their union. The result of the
+command is the canonical serialization of this unified table of
+contents.
+
+[para]
+Title and label of the resulting table are taken from the table
+contained in [arg serialb].
+
+[para]
+The whole table and its divisions are merged recursively in the same
+manner:
+
+[list_begin enumerated]
+
+[enum]
+All reference elements which occur in both divisions (identified by
+their label) are unified with document id's and descriptions taken
+from the second table.
+
+[enum]
+All division elements which occur in both divisions (identified by
+their label) are unified with the optional document id taken from the
+second table, if any, or from the first if none is in the second. The
+elements in the division are merged recursively using the same
+algorithm as described in this list.
+
+[enum]
+Type conflicts between elements, i.e. finding two elements with the
+same label but different types result in a merge error.
+
+[enum]
+All elements found in the second division but not in the first are
+added to the end of the list of elements in the merge result.
+[list_end]
+
+[para]
+
+For the specification of regular and canonical serializations see the
+section [sectref {ToC serialization format}].
+
+[list_end]
+
+[include include/serialization.inc]
+
+[vset CATEGORY doctools]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]