doctools.tcl

Go to the documentation of this file.
00001 /*  doctools.tcl --*/
00002 /* */
00003 /*  Implementation of doctools objects for Tcl.*/
00004 /* */
00005 /*  Copyright (c) 2003-2007 Andreas Kupries <andreas_kupries@sourceforge.net>*/
00006 /* */
00007 /*  See the file "license.terms" for information on usage and redistribution*/
00008 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00009 /*  */
00010 /*  RCS: @(#) $Id: doctools.tcl,v 1.22 2007/08/20 20:11:59 andreas_kupries Exp $*/
00011 
00012 package require Tcl 8.2
00013 package require textutil::expander
00014 
00015 /*  @mdgen OWNER: api.tcl*/
00016 /*  @mdgen OWNER: checker.tcl*/
00017 /*  @mdgen OWNER: mpformats/*.tcl*/
00018 /*  @mdgen OWNER: mpformats/*.msg*/
00019 /*  @mdgen OWNER: mpformats/fmt.**/
00020 
00021 namespace ::doctools {
00022     /*  Data storage in the doctools module*/
00023     /*  -------------------------------*/
00024     /* */
00025     /*  One namespace per object, containing*/
00026     /*   1) A list of additional search paths for format definition files.*/
00027     /*      This list extends the list of standard paths known to the module.*/
00028     /*      The paths in the list are searched before the standard paths.*/
00029     /*   2) Configuration information*/
00030     /*      a) string:  The format to use when converting the input.*/
00031     /*      b) boolean: A flag telling us whether to warn when visual markup*/
00032     /*         is used in the input, or not.*/
00033     /*      c) File information associated with the input, if any.*/
00034     /*      d) Module information associated with the input, if any.*/
00035     /*      e) Copyright information, if any*/
00036     /*   4) Name of the interpreter used to perform the syntax check of the*/
00037     /*      input (= allowed order of formatting commands).*/
00038     /*   5) Name of the interpreter containing the code coming from the format*/
00039     /*      definition file.*/
00040     /*   6) Name of the expander object used to interpret the input to convert.*/
00041 
00042     /*  commands is the list of subcommands recognized by the doctools objects*/
00043     variable commands [list     \
00044         "cget"          \
00045         "configure"         \
00046         "destroy"           \
00047         "format"            \
00048         "map"           \
00049         "search"            \
00050         "warnings"                  \
00051         "parameters"                \
00052         "param = "                  \
00053         ]
00054 
00055     /*  Only export the toplevel commands*/
00056     namespace export new search help
00057 
00058     /*  Global data*/
00059 
00060     /*   1) List of standard paths to look at when searching for a format*/
00061     /*      definition. Extensible.*/
00062     /*   2) Location of this file in the filesystem*/
00063 
00064     variable paths [list]
00065     variable here [file dirname [info script]]
00066 }
00067 
00068 /*  ::doctools::search --*/
00069 /* */
00070 /*  Extend the list of paths used when searching for format definition files.*/
00071 /* */
00072 /*  Arguments:*/
00073 /*  path    Path to add to the list. The path has to exist, has to be a*/
00074 /*                directory, and has to be readable.*/
00075 /* */
00076 /*  Results:*/
00077 /*  None.*/
00078 /* */
00079 /*  Sideeffects:*/
00080 /*  The specified path is added to the front of the list of search*/
00081 /*  paths. This means that the new path is search before the*/
00082 /*  standard paths set at module initialization time.*/
00083 
00084 ret  ::doctools::search (type path) {
00085     variable paths
00086 
00087     if {![file exists      $path]} {return -code error "doctools::search: path does not exist"}
00088     if {![file isdirectory $path]} {return -code error "doctools::search: path is not a directory"}
00089     if {![file readable    $path]} {return -code error "doctools::search: path cannot be read"}
00090 
00091     set paths [linsert $paths 0 $path]
00092     return
00093 }
00094 
00095 /*  ::doctools::help --*/
00096 /* */
00097 /*  Return a string containing short help*/
00098 /*  regarding the existing formatting commands.*/
00099 /* */
00100 /*  Arguments:*/
00101 /*  None.*/
00102 /* */
00103 /*  Results:*/
00104 /*  A string.*/
00105 
00106 ret  ::doctools::help () {
00107     return "formatting commands\n\
00108         * manpage_begin - begin of manpage\n\
00109         * moddesc       - module description\n\
00110         * titledesc     - manpage title\n\
00111         * copyright     - copyright assignment\n\
00112         * manpage_end   - end of manpage\n\
00113         * require       - package requirement\n\
00114         * description   - begin of manpage body\n\
00115         * section       - begin new section of body\n\
00116         * subsection    - begin new sub-section of body\n\
00117         * para          - begin new paragraph\n\
00118         * list_begin    - begin a list\n\
00119         * list_end      - end of a list\n\
00120         * lst_item      - begin item of definition list\n\
00121         * call          - command definition, adds to synopsis\n\
00122         * usage         - see above, without adding to synopsis\n\
00123         * bullet        - begin item in bulleted list\n\
00124         * enum          - begin item in enumerated list\n\
00125         * arg_def       - begin item in argument list\n\
00126         * cmd_def       - begin item in command list\n\
00127         * opt_def       - begin item in option list\n\
00128         * tkoption_def  - begin item in tkoption list\n\
00129         * example       - example block\n\
00130         * example_begin - begin example\n\
00131         * example_end   - end of example\n\
00132         * see_also      - cross reference declaration\n\
00133         * keywords      - keyword declaration\n\
00134         * nl            - paragraph break in list items\n\
00135         * arg           - semantic markup - argument\n\
00136         * cmd           - semantic markup - command\n\
00137         * opt           - semantic markup - optional data\n\
00138         * comment       - semantic markup - comment\n\
00139         * sectref       - semantic markup - section reference\n\
00140         * syscmd        - semantic markup - system command\n\
00141         * method        - semantic markup - object method\n\
00142         * namespace     - semantic markup - namespace name\n\
00143         * option        - semantic markup - option\n\
00144         * widget        - semantic markup - widget\n\
00145         * fun           - semantic markup - function\n\
00146         * type          - semantic markup - data type\n\
00147         * package       - semantic markup - package\n\
00148         * class         - semantic markup - class\n\
00149         * var           - semantic markup - variable\n\
00150         * file          - semantic markup - file \n\
00151         * uri           - semantic markup - uri (optional label)\n\
00152         * term          - semantic markup - unspecific terminology\n\
00153         * const         - semantic markup - constant value\n\
00154         * emph          - emphasis\n\
00155         * strong        - emphasis, deprecated, usage is discouraged\n\
00156         "
00157 }
00158 
00159 /*  ::doctools::new --*/
00160 /* */
00161 /*  Create a new doctools object with a given name. May configure the object.*/
00162 /* */
00163 /*  Arguments:*/
00164 /*  name    Name of the doctools object.*/
00165 /*  args    Options configuring the new object.*/
00166 /* */
00167 /*  Results:*/
00168 /*  name    Name of the doctools created*/
00169 
00170 ret  ::doctools::new (type name , type args) {
00171     
00172     if { [llength [info commands ::$name]] } {
00173     return -code error "command \"$name\" already exists, unable to create doctools object"
00174     }
00175     if {[llength $args] % 2 == 1} {
00176     return -code error "wrong # args: doctools::new name ?opt val...??"
00177     }
00178 
00179     # The arguments seem to be ok, setup the namespace for the object
00180 
00181     namespace eval ::doctools::doctools$name {
00182     variable paths      [list]
00183     variable format     ""
00184     variable formatfile ""
00185     variable deprecated 0
00186     variable file       ""
00187     variable module     ""
00188     variable copyright  ""
00189     variable format_ip  ""
00190     variable chk_ip     ""
00191     variable expander   "[namespace current]::ex"
00192     variable ex_ok      0
00193     variable msg        [list]
00194     variable param      [list]
00195     variable map ;      array set map {}
00196     }
00197 
00198     # Create the command to manipulate the object
00199     #                 $name -> ::doctools::DoctoolsProc $name
00200     interp alias {} ::$name {} ::doctools::DoctoolsProc $name
00201 
00202     # If the name was followed by arguments use them to configure the
00203     # object before returning its handle to the caller.
00204 
00205     if {[llength $args] > 1} {
00206     # Use linsert trick to make the command a pure list.
00207     eval [linsert $args 0 _configure $name]
00208     }
00209     return $name
00210 }
00211 
00212 /* */
00213 /*  Private functions follow*/
00214 
00215 /*  ::doctools::DoctoolsProc --*/
00216 /* */
00217 /*  Command that processes all doctools object commands.*/
00218 /*  Dispatches any object command to the appropriate internal*/
00219 /*  command implementing its functionality.*/
00220 /* */
00221 /*  Arguments:*/
00222 /*  name    Name of the doctools object to manipulate.*/
00223 /*  cmd Subcommand to invoke.*/
00224 /*  args    Arguments for subcommand.*/
00225 /* */
00226 /*  Results:*/
00227 /*  Varies based on command to perform*/
00228 
00229 ret  ::doctools::DoctoolsProc (type name , optional cmd ="" , type args) {
00230     # Do minimal args checks here
00231     if { [llength [info level 0]] == 2 } {
00232     error "wrong # args: should be \"$name option ?arg arg ...?\""
00233     }
00234     
00235     # Split the args into command and args components
00236 
00237     if { [llength [info commands ::doctools::_$cmd]] == 0 } {
00238     variable commands
00239     set optlist [join $commands ", "]
00240     set optlist [linsert $optlist "end-1" "or"]
00241     return -code error "bad option \"$cmd\": must be $optlist"
00242     }
00243     return [eval [list ::doctools::_$cmd $name] $args]
00244 }
00245 
00246 /* */
00247 /*  Method implementations follow (these are also private commands)*/
00248 
00249 /*  ::doctools::_cget --*/
00250 /* */
00251 /*  Retrieve the current value of a particular option*/
00252 /* */
00253 /*  Arguments:*/
00254 /*  name    Name of the doctools object to query*/
00255 /*  option  Name of the option whose value we are asking for.*/
00256 /* */
00257 /*  Results:*/
00258 /*  The value of the option*/
00259 
00260 ret  ::doctools::_cget (type name , type option) {
00261     _configure $name $option
00262 }
00263 
00264 /*  ::doctools::_configure --*/
00265 /* */
00266 /*  Configure a doctools object, or query its configuration.*/
00267 /* */
00268 /*  Arguments:*/
00269 /*  name    Name of the doctools object to configure*/
00270 /*  args    Options and their values.*/
00271 /* */
00272 /*  Results:*/
00273 /*  None if configuring the object.*/
00274 /*  A list of all options and their values if called without arguments.*/
00275 /*  The value of one particular option if called with a single argument.*/
00276 
00277 ret  ::doctools::_configure (type name , type args) {
00278     upvar ::doctools::doctools${name}::format_ip  format_ip
00279     upvar ::doctools::doctools${name}::chk_ip     chk_ip
00280     upvar ::doctools::doctools${name}::expander   expander
00281     upvar ::doctools::doctools${name}::passes     passes
00282 
00283     if {[llength $args] == 0} {
00284     # Retrieve the current configuration.
00285 
00286     upvar ::doctools::doctools${name}::file       file
00287     upvar ::doctools::doctools${name}::module     module
00288     upvar ::doctools::doctools${name}::format     format
00289     upvar ::doctools::doctools${name}::copyright  copyright
00290     upvar ::doctools::doctools${name}::deprecated deprecated
00291 
00292     set     res [list]
00293     lappend res -file       $file
00294     lappend res -module     $module
00295     lappend res -format     $format
00296     lappend res -copyright  $copyright
00297     lappend res -deprecated $deprecated
00298     return $res
00299 
00300     } elseif {[llength $args] == 1} {
00301     # Query the value of one particular option.
00302 
00303     switch -exact -- [lindex $args 0] {
00304         -file {
00305         upvar ::doctools::doctools${name}::file file
00306         return $file
00307         }
00308         -module {
00309         upvar ::doctools::doctools${name}::module module
00310         return $module
00311         }
00312         -copyright {
00313         upvar ::doctools::doctools${name}::copyright copyright
00314         return $copyright
00315         }
00316         -format {
00317         upvar ::doctools::doctools${name}::format format
00318         return $format
00319         }
00320         -deprecated {
00321         upvar ::doctools::doctools${name}::deprecated deprecated
00322         return $deprecated
00323         }
00324         default {
00325         return -code error \
00326             "doctools::_configure: Unknown option \"[lindex $args 0]\", expected\
00327             -copyright, -file, -module, -format, or -deprecated"
00328         }
00329     }
00330     } else {
00331     # Reconfigure the object.
00332 
00333     if {[llength $args] % 2 == 1} {
00334         return -code error "wrong # args: doctools::_configure name ?opt val...??"
00335     }
00336 
00337     foreach {option value} $args {
00338         switch -exact -- $option {
00339         -file {
00340             upvar ::doctools::doctools${name}::file file
00341             set file $value
00342         }
00343         -module {
00344             upvar ::doctools::doctools${name}::module module
00345             set module $value
00346         }
00347         -copyright {
00348             upvar ::doctools::doctools${name}::copyright copyright
00349             set copyright $value
00350         }
00351         -format {
00352             if {[catch {
00353             set fmtfile [LookupFormat $name $value]
00354             SetupFormatter $name $fmtfile
00355             upvar ::doctools::doctools${name}::format format
00356             set format $value
00357             } msg]} {
00358             return -code error "doctools::_configure: -format: $msg"
00359             }
00360         }
00361         -deprecated {
00362             if {![string is boolean $value]} {
00363             return -code error \
00364                 "doctools::_configure: -deprecated expected a boolean, got \"$value\""
00365             }
00366             upvar ::doctools::doctools${name}::deprecated deprecated
00367             set deprecated $value
00368         }
00369         default {
00370             return -code error \
00371                 "doctools::_configure: Unknown option \"$option\", expected\
00372                 -copyright, -file, -module, -format, or -deprecated"
00373         }
00374         }
00375     }
00376     }
00377     return ""
00378 }
00379 
00380 /*  ::doctools::_destroy --*/
00381 /* */
00382 /*  Destroy a doctools object, including its associated command and data storage.*/
00383 /* */
00384 /*  Arguments:*/
00385 /*  name    Name of the doctools object to destroy.*/
00386 /* */
00387 /*  Results:*/
00388 /*  None.*/
00389 
00390 ret  ::doctools::_destroy (type name) {
00391     # Check the object for sub objects which have to destroyed before
00392     # the namespace is torn down.
00393     namespace eval ::doctools::doctools$name {
00394     if {$format_ip != ""} {interp delete $format_ip}
00395     if {$chk_ip    != ""} {interp delete $chk_ip}
00396 
00397     # Expander objects have no delete/destroy method. This would
00398     # be a leak if not for the fact that an expander object is a
00399     # namespace, and we have arranged to make it a sub namespace of
00400     # the doctools object. Therefore tearing down our object namespace
00401     # also cleans up the expander object.
00402     # if {$expander != ""} {$expander destroy}
00403 
00404     }
00405     namespace delete ::doctools::doctools$name
00406     interp alias {} ::$name {}
00407     return
00408 }
00409 
00410 /*  ::doctools::_map --*/
00411 /* */
00412 /*  Add a mapping from symbolic to actual filename to the object.*/
00413 /* */
00414 /*  Arguments:*/
00415 /*  name    Name of the doctools object to use*/
00416 /*  sfname  Symbolic filename to map*/
00417 /*  afname  Actual filename*/
00418 /* */
00419 /*  Results:*/
00420 /*  None.*/
00421 
00422 ret  ::doctools::_map (type name , type sfname , type afname) {
00423     upvar ::doctools::doctools${name}::map map
00424     set map($sfname) $afname
00425     return
00426 }
00427 
00428 /*  ::doctools::_format --*/
00429 /* */
00430 /*  Convert some text in doctools format*/
00431 /*  according to the configuration in the object.*/
00432 /* */
00433 /*  Arguments:*/
00434 /*  name    Name of the doctools object to use*/
00435 /*  text    Text to convert.*/
00436 /* */
00437 /*  Results:*/
00438 /*  The conversion result.*/
00439 
00440 ret  ::doctools::_format (type name , type text) {
00441     upvar ::doctools::doctools${name}::format format
00442     if {$format == ""} {
00443     return -code error "$name: No format was specified"
00444     }
00445 
00446     upvar ::doctools::doctools${name}::format_ip format_ip
00447     upvar ::doctools::doctools${name}::chk_ip    chk_ip
00448     upvar ::doctools::doctools${name}::ex_ok     ex_ok
00449     upvar ::doctools::doctools${name}::expander  expander
00450     upvar ::doctools::doctools${name}::passes    passes
00451     upvar ::doctools::doctools${name}::msg       warnings
00452 
00453     if {!$ex_ok}       {SetupExpander  $name}
00454     if {$chk_ip == ""} {SetupChecker   $name}
00455     # assert (format_ip != "")
00456 
00457     set warnings [list]
00458     if {[catch {$format_ip eval fmt_initialize}]} {
00459     return -code error "Could not initialize engine"
00460     }
00461     set result ""
00462 
00463     for {
00464     set p $passes ; set n 1
00465     } {
00466     $p > 0
00467     } {
00468     incr p -1 ; incr n
00469     } {
00470     if {[catch {$format_ip eval [list fmt_setup $n]}]} {
00471         catch {$format_ip eval fmt_shutdown}
00472         return -code error "Could not initialize pass $n of engine"
00473     }
00474     $chk_ip eval ck_initialize
00475 
00476     if {[catch {set result [$expander expand $text]} msg]} {
00477         catch {$format_ip eval fmt_shutdown}
00478         # Filter for checker errors and reduce them to the essential message.
00479 
00480         if {![regexp {^Error in} $msg]}          {return -code error $msg}
00481         #set msg [join [lrange [split $msg \n] 2 end]]
00482 
00483         if {![regexp {^--> \(FmtError\) } $msg]} {return -code error "Doctools $msg"}
00484         set msg [lindex [split $msg \n] 0]
00485         regsub {^--> \(FmtError\) } $msg {} msg
00486 
00487         return -code error $msg
00488     }
00489 
00490     $chk_ip eval ck_complete
00491     }
00492 
00493     if {[catch {set result [$format_ip eval [list fmt_postprocess $result]]}]} {
00494     return -code error "Unable to post process final result"
00495     }
00496     if {[catch {$format_ip eval fmt_shutdown}]} {
00497     return -code error "Could not shut engine down"
00498     }
00499     return $result
00500 
00501 }
00502 
00503 /*  ::doctools::_search --*/
00504 /* */
00505 /*  Add a search path to the object.*/
00506 /* */
00507 /*  Arguments:*/
00508 /*  name    Name of the doctools object to extend*/
00509 /*  path    Search path to add.*/
00510 /* */
00511 /*  Results:*/
00512 /*  None.*/
00513 
00514 ret  ::doctools::_search (type name , type path) {
00515     if {![file exists      $path]} {return -code error "$name search: path does not exist"}
00516     if {![file isdirectory $path]} {return -code error "$name search: path is not a directory"}
00517     if {![file readable    $path]} {return -code error "$name search: path cannot be read"}
00518 
00519     upvar ::doctools::doctools${name}::paths paths
00520     set paths [linsert $paths 0 $path]
00521     return
00522 }
00523 
00524 /*  ::doctools::_warnings --*/
00525 /* */
00526 /*  Return the warning accumulated during the last invocation of 'format'.*/
00527 /* */
00528 /*  Arguments:*/
00529 /*  name    Name of the doctools object to query*/
00530 /* */
00531 /*  Results:*/
00532 /*  A list of warnings.*/
00533 
00534 ret  ::doctools::_warnings (type name) {
00535     upvar ::doctools::doctools${name}::msg msg
00536     return $msg
00537 }
00538 
00539 /*  ::doctools::_parameters --*/
00540 /* */
00541 /*  Returns a list containing the parameters provided*/
00542 /*  by the selected formatting engine.*/
00543 /* */
00544 /*  Arguments:*/
00545 /*  name    Name of the doctools object to query*/
00546 /* */
00547 /*  Results:*/
00548 /*  A list of parameter names*/
00549 
00550 ret  ::doctools::_parameters (type name) {
00551     upvar ::doctools::doctools${name}::param param
00552     return $param
00553 }
00554 
00555 /*  ::doctools::_setparam --*/
00556 /* */
00557 /*  Set a named engine parameter to a value.*/
00558 /* */
00559 /*  Arguments:*/
00560 /*  name    Name of the doctools object to query*/
00561 /*  param   Name of the parameter to set.*/
00562 /*  value   Value to set the parameter to.*/
00563 /* */
00564 /*  Results:*/
00565 /*  None.*/
00566 
00567 ret  ::doctools::_setparam (type name , type param , type value) {
00568     upvar ::doctools::doctools${name}::format_ip format_ip
00569 
00570     if {$format_ip == {}} {
00571     return -code error \
00572         "Unable to set parameters without a valid format"
00573     }
00574 
00575     $format_ip eval [list fmt_varset $param $value]
00576     return
00577 }
00578 
00579 /* */
00580 /*  Support commands*/
00581 
00582 /*  ::doctools::LookupFormat --*/
00583 /* */
00584 /*  Search a format definition file based upon its name*/
00585 /* */
00586 /*  Arguments:*/
00587 /*  name    Name of the doctools object to use*/
00588 /*  format  Name of the format to look for.*/
00589 /* */
00590 /*  Results:*/
00591 /*  The file containing the format definition*/
00592 
00593 ret  ::doctools::LookupFormat (type name , type format) {
00594     # Order of searching
00595     # 1) Is the name of the format an existing file ?
00596     #    If yes, take this file.
00597     # 2) Look for the file in the directories given to the object itself..
00598     # 3) Look for the file in the standard directories of this package.
00599 
00600     if {[file exists $format]} {
00601     return $format
00602     }
00603 
00604     upvar ::doctools::doctools${name}::paths opaths
00605     foreach path $opaths {
00606     set f [file join $path fmt.$format]
00607     if {[file exists $f]} {
00608         return $f
00609     }
00610     }
00611 
00612     variable paths
00613     foreach path $paths {
00614     set f [file join $path fmt.$format]
00615     if {[file exists $f]} {
00616         return $f
00617     }
00618     }
00619 
00620     return -code error "Unknown format \"$format\""
00621 }
00622 
00623 /*  ::doctools::SetupFormatter --*/
00624 /* */
00625 /*  Create and initializes an interpreter containing a*/
00626 /*  formatting engine*/
00627 /* */
00628 /*  Arguments:*/
00629 /*  name    Name of the doctools object to manipulate*/
00630 /*  format  Name of file containing the code of the engine*/
00631 /* */
00632 /*  Results:*/
00633 /*  None.*/
00634 
00635 ret  ::doctools::SetupFormatter (type name , type format) {
00636 
00637     # Create and initialize the interpreter first.
00638     # Use a transient variable. Interrogate the
00639     # engine and check its response. Bail out in
00640     # case of errors. Only if we pass the checks
00641     # we tear down the old engine and make the new
00642     # one official.
00643 
00644     variable here
00645     set mpip [interp create -safe] ; # interpreter for the formatting engine
00646     $mpip eval [list set auto_path $::auto_path]
00647     #set mpip [interp create] ; # interpreter for the formatting engine
00648 
00649     $mpip invokehidden source [file join $here api.tcl]
00650     #$mpip eval [list source [file join $here api.tcl]]
00651     interp alias $mpip dt_source   {} ::doctools::Source  $mpip [file dirname $format]
00652     interp alias $mpip dt_package  {} ::doctools::Package $mpip
00653     interp alias $mpip file        {} ::doctools::FileOp  $mpip
00654     interp alias $mpip puts_stderr {} ::puts stderr
00655     $mpip invokehidden source $format
00656     #$mpip eval [list source $format]
00657 
00658     # Check the engine for useability in doctools.
00659 
00660     foreach api {
00661     fmt_numpasses
00662     fmt_initialize
00663     fmt_setup
00664     fmt_postprocess
00665     fmt_shutdown
00666     fmt_listvariables
00667     fmt_varset
00668     } {
00669     if {[$mpip eval [list info commands $api]] == {}} {
00670         interp delete $mpip
00671         error "$format error: API incomplete, cannot use this engine"
00672     }
00673     }
00674     if {[catch {
00675     set passes [$mpip eval fmt_numpasses]
00676     }]} {
00677     interp delete $mpip
00678     error "$format error: Unable to query for number of passes"
00679     }
00680     if {![string is integer $passes] || ($passes < 1)} {
00681     interp delete $mpip
00682     error "$format error: illegal number of passes \"$passes\""
00683     }
00684     if {[catch {
00685     set parameters [$mpip eval fmt_listvariables]
00686     }]} {
00687     interp delete $mpip
00688     error "$format error: Unable to query for list of parameters"
00689     }
00690 
00691     # Passed the tests. Tear down existing engine,
00692     # and checker. The latter is destroyed because
00693     # of its aliases into the formatter, which are
00694     # now invalid. It will be recreated during the
00695     # next call of 'format'.
00696 
00697     upvar ::doctools::doctools${name}::formatfile formatfile
00698     upvar ::doctools::doctools${name}::format_ip  format_ip
00699     upvar ::doctools::doctools${name}::chk_ip     chk_ip
00700     upvar ::doctools::doctools${name}::expander   expander
00701     upvar ::doctools::doctools${name}::passes     xpasses
00702     upvar ::doctools::doctools${name}::param      xparam
00703 
00704     if {$chk_ip != {}}    {interp delete $chk_ip}
00705     if {$format_ip != {}} {interp delete $format_ip}
00706 
00707     set chk_ip    ""
00708     set format_ip ""
00709 
00710     # Now link engine API into it.
00711 
00712     interp alias $mpip dt_file      {} ::doctools::GetFile      $name
00713     interp alias $mpip dt_fileid    {} ::doctools::GetFileId    $name
00714     interp alias $mpip dt_module    {} ::doctools::GetModule    $name
00715     interp alias $mpip dt_copyright {} ::doctools::GetCopyright $name
00716     interp alias $mpip dt_format    {} ::doctools::GetFormat    $name
00717     interp alias $mpip dt_user      {} ::doctools::GetUser      $name
00718     interp alias $mpip dt_lnesting  {} ::doctools::ListLevel    $name
00719     interp alias $mpip dt_fmap      {} ::doctools::MapFile      $name
00720     interp alias $mpip file         {} ::doctools::FileCmd
00721 
00722     foreach cmd {cappend cget cis cname cpop cpush ctopandclear cset lb rb} {
00723     interp alias $mpip ex_$cmd {} $expander $cmd
00724     }
00725 
00726     set format_ip  $mpip
00727     set formatfile $format
00728     set xpasses    $passes
00729     set xparam     $parameters
00730     return
00731 }
00732 
00733 /*  ::doctools::SetupChecker --*/
00734 /* */
00735 /*  Create and initializes an interpreter for checking the usage of*/
00736 /*  doctools formatting commands*/
00737 /* */
00738 /*  Arguments:*/
00739 /*  name    Name of the doctools object to manipulate*/
00740 /* */
00741 /*  Results:*/
00742 /*  None.*/
00743 
00744 ret  ::doctools::SetupChecker (type name) {
00745     # Create an interpreter for checking the usage of doctools formatting commands
00746     # and initialize it: Link it to the interpreter doing the formatting, the
00747     # expander object and the configuration information. All of which
00748     # is accessible through the token/handle (name of state/object array).
00749 
00750     variable here
00751 
00752     upvar ::doctools::doctools${name}::chk_ip    chk_ip
00753     if {$chk_ip != ""} {return}
00754 
00755     upvar ::doctools::doctools${name}::expander  expander
00756     upvar ::doctools::doctools${name}::format_ip format_ip
00757 
00758     set chk_ip [interp create] ; # interpreter hosting the formal format checker
00759 
00760     # Make configuration available through command, then load the code base.
00761 
00762     foreach {cmd ckcmd} {
00763     dt_search     SearchPaths
00764     dt_deprecated Deprecated
00765     dt_error      FmtError
00766     dt_warning    FmtWarning
00767     dt_where      Where
00768     } {
00769     interp alias $chk_ip $cmd {} ::doctools::$ckcmd $name
00770     }
00771     $chk_ip eval [list source [file join $here checker.tcl]]
00772 
00773     # Simple expander commands are directly routed back into it, no
00774     # checking required.
00775 
00776     foreach cmd {cappend cget cis cname cpop cpush ctopandclear cset lb rb} {
00777     interp alias $chk_ip $cmd {} $expander $cmd
00778     }
00779 
00780     # Link the formatter commands into the checker. We use the prefix
00781     # 'fmt_' to distinguish them from the checking commands.
00782 
00783     foreach cmd {
00784     manpage_begin moddesc titledesc copyright manpage_end require
00785     description section para list_begin list_end lst_item call
00786     bullet enum example example_begin example_end see_also
00787     keywords nl arg cmd opt comment sectref syscmd method option
00788     widget fun type package class var file uri usage term const
00789     arg_def cmd_def opt_def tkoption_def emph strong plain_text
00790     namespace subsection
00791     } {
00792     interp alias $chk_ip fmt_$cmd $format_ip fmt_$cmd
00793     }
00794     return
00795 }
00796 
00797 /*  ::doctools::SetupExpander --*/
00798 /* */
00799 /*  Create and initializes the expander for input*/
00800 /* */
00801 /*  Arguments:*/
00802 /*  name    Name of the doctools object to manipulate*/
00803 /* */
00804 /*  Results:*/
00805 /*  None.*/
00806 
00807 ret  ::doctools::SetupExpander (type name) {
00808     upvar ::doctools::doctools${name}::ex_ok    ex_ok
00809     if {$ex_ok} {return}
00810 
00811     upvar ::doctools::doctools${name}::expander expander
00812     ::textutil::expander $expander
00813     $expander evalcmd [list ::doctools::Eval $name]
00814     $expander textcmd plain_text
00815     set ex_ok 1
00816     return
00817 }
00818 
00819 /*  ::doctools::SearchPaths --*/
00820 /* */
00821 /*  API for checker. Returns list of search paths for format*/
00822 /*  definitions. Used to look for message catalogs as well.*/
00823 /* */
00824 /*  Arguments:*/
00825 /*  name    Name of the doctools object to query.*/
00826 /* */
00827 /*  Results:*/
00828 /*  None.*/
00829 
00830 ret  ::doctools::SearchPaths (type name) {
00831     upvar ::doctools::doctools${name}::paths opaths
00832     variable paths
00833 
00834     set p $opaths
00835     foreach s $paths {lappend p $s}
00836     return $p
00837 }
00838 
00839 /*  ::doctools::Deprecated --*/
00840 /* */
00841 /*  API for checker. Returns flag determining*/
00842 /*  whether visual markup is warned against, or not.*/
00843 /* */
00844 /*  Arguments:*/
00845 /*  name    Name of the doctools object to query.*/
00846 /* */
00847 /*  Results:*/
00848 /*  None.*/
00849 
00850 ret  ::doctools::Deprecated (type name) {
00851     upvar ::doctools::doctools${name}::deprecated deprecated
00852     return $deprecated
00853 }
00854 
00855 /*  ::doctools::FmtError --*/
00856 /* */
00857 /*  API for checker. Called when an error occurred.*/
00858 /* */
00859 /*  Arguments:*/
00860 /*  name    Name of the doctools object to query.*/
00861 /*  text    Error message*/
00862 /* */
00863 /*  Results:*/
00864 /*  None.*/
00865 
00866 ret  ::doctools::FmtError (type name , type text) {
00867     return -code error "(FmtError) $text"
00868 }
00869 
00870 /*  ::doctools::FmtWarning --*/
00871 /* */
00872 /*  API for checker. Called when a warning was generated*/
00873 /* */
00874 /*  Arguments:*/
00875 /*  name    Name of the doctools object*/
00876 /*  text    Warning message*/
00877 /* */
00878 /*  Results:*/
00879 /*  None.*/
00880 
00881 ret  ::doctools::FmtWarning (type name , type text) {
00882     upvar ::doctools::doctools${name}::msg msg
00883     lappend msg $text
00884     return
00885 }
00886 
00887 /*  ::doctools::Where --*/
00888 /* */
00889 /*  API for checker. Called when the current location is needed*/
00890 /* */
00891 /*  Arguments:*/
00892 /*  name    Name of the doctools object*/
00893 /* */
00894 /*  Results:*/
00895 /*  List containing offset, line, column*/
00896 
00897 ret  ::doctools::Where (type name) {
00898     upvar ::doctools::doctools${name}::expander expander
00899     return [$expander where]
00900 }
00901 
00902 /*  ::doctools::Eval --*/
00903 /* */
00904 /*  API for expander. Routes the macro invocations*/
00905 /*  into the checker interpreter*/
00906 /* */
00907 /*  Arguments:*/
00908 /*  name    Name of the doctools object to query.*/
00909 /* */
00910 /*  Results:*/
00911 /*  None.*/
00912 
00913 ret  ::doctools::Eval (type name , type macro) {
00914     upvar ::doctools::doctools${name}::chk_ip chk_ip
00915 
00916     #puts stderr "\t\t$name [lindex [split $macro] 0]"
00917 
00918     # Handle the [include] command directly
00919     if {[string match include* $macro]} {
00920     foreach {cmd filename} $macro break
00921     return [ExpandInclude $name $filename]
00922     }
00923 
00924     # Rewrite the [namespace] command before passing it on.
00925     # "namespace" is a special command. The interpreter the validator
00926     # resides in uses the package "msgcat", which in turn uses the
00927     # builtin namespace. So the builtin cannot be simply
00928     # overwritten. We use a different name.
00929 
00930     if {[string match namespace* $macro]} {
00931     set macro _$macro
00932     }
00933     return [$chk_ip eval $macro]
00934 }
00935 
00936 /*  ::doctools::ExpandInclude --*/
00937 /* */
00938 /*  Handle inclusion of files.*/
00939 /* */
00940 /*  Arguments:*/
00941 /*  name    Name of the doctools object to query.*/
00942 /*  path    Name of file to include and expand.*/
00943 /* */
00944 /*  Results:*/
00945 /*  None.*/
00946 
00947 ret  ::doctools::ExpandInclude (type name , type path) {
00948     upvar ::doctools::doctools${name}::file file
00949 
00950     set ipath [file join [file dirname $file] $path]
00951     if {![file exists $ipath]} {
00952     set ipath $path
00953     if {![file exists $ipath]} {
00954         return -code error "Unable to find include file \"$path\""
00955     }
00956     }
00957 
00958     set    chan [open $ipath r]
00959     set    text [read $chan]
00960     close $chan
00961 
00962     upvar ::doctools::doctools${name}::expander  expander
00963 
00964     return [$expander expand $text]
00965 }
00966 
00967 /*  ::doctools::GetUser --*/
00968 /* */
00969 /*  API for formatter. Returns name of current user*/
00970 /* */
00971 /*  Arguments:*/
00972 /*  name    Name of the doctools object to query.*/
00973 /* */
00974 /*  Results:*/
00975 /*  String, name of current user.*/
00976 
00977 ret  ::doctools::GetUser (type name) {
00978     global  tcl_platform
00979     return $tcl_platform(user)
00980 }
00981 
00982 /*  ::doctools::GetFile --*/
00983 /* */
00984 /*  API for formatter. Returns file information*/
00985 /* */
00986 /*  Arguments:*/
00987 /*  name    Name of the doctools object to query.*/
00988 /* */
00989 /*  Results:*/
00990 /*  File information*/
00991 
00992 ret  ::doctools::GetFile (type name) {
00993 
00994     #puts stderr "GetFile $name"
00995 
00996     upvar ::doctools::doctools${name}::file file
00997 
00998     #puts stderr "ok $file"
00999     return $file
01000 }
01001 
01002 /*  ::doctools::GetFileId --*/
01003 /* */
01004 /*  API for formatter. Returns file information (truncated to stem of filename)*/
01005 /* */
01006 /*  Arguments:*/
01007 /*  name    Name of the doctools object to query.*/
01008 /* */
01009 /*  Results:*/
01010 /*  File information*/
01011 
01012 ret  ::doctools::GetFileId (type name) {
01013     return [file rootname [file tail [GetFile $name]]]
01014 }
01015 
01016 /*  ::doctools::FileCmd --*/
01017 /* */
01018 /*  API for formatter. Restricted implementation of file.*/
01019 /* */
01020 /*  Arguments:*/
01021 /*  name    Name of the doctools object to query.*/
01022 /* */
01023 /*  Results:*/
01024 /*  Module information*/
01025 
01026 ret  ::doctools::FileCmd (type cmd , type args) {
01027     switch -exact -- $cmd {
01028     split {return [eval file split $args]}
01029     join  {return [eval file join $args]}
01030     }
01031     return -code error "Illegal subcommand: $cmd $args"
01032 }
01033 
01034 /*  ::doctools::GetModule --*/
01035 /* */
01036 /*  API for formatter. Returns module information*/
01037 /* */
01038 /*  Arguments:*/
01039 /*  name    Name of the doctools object to query.*/
01040 /* */
01041 /*  Results:*/
01042 /*  Module information*/
01043 
01044 ret  ::doctools::GetModule (type name) {
01045     upvar ::doctools::doctools${name}::module module
01046     return   $module
01047 }
01048 
01049 /*  ::doctools::GetCopyright --*/
01050 /* */
01051 /*  API for formatter. Returns copyright information*/
01052 /* */
01053 /*  Arguments:*/
01054 /*  name    Name of the doctools object to query.*/
01055 /* */
01056 /*  Results:*/
01057 /*  Copyright information*/
01058 
01059 ret  ::doctools::GetCopyright (type name) {
01060     upvar ::doctools::doctools${name}::copyright copyright
01061     return   $copyright
01062 }
01063 
01064 /*  ::doctools::GetFormat --*/
01065 /* */
01066 /*  API for formatter. Returns format information*/
01067 /* */
01068 /*  Arguments:*/
01069 /*  name    Name of the doctools object to query.*/
01070 /* */
01071 /*  Results:*/
01072 /*  Format information*/
01073 
01074 ret  ::doctools::GetFormat (type name) {
01075     upvar ::doctools::doctools${name}::format format
01076     return $format
01077 }
01078 
01079 /*  ::doctools::ListLevel --*/
01080 /* */
01081 /*  API for formatter. Returns number of open lists*/
01082 /* */
01083 /*  Arguments:*/
01084 /*  name    Name of the doctools object to query.*/
01085 /* */
01086 /*  Results:*/
01087 /*  Boolean flag.*/
01088 
01089 ret  ::doctools::ListLevel (type name) {
01090     upvar ::doctools::doctools${name}::chk_ip chk_ip
01091     return [$chk_ip eval LNest]
01092 }
01093 
01094 /*  ::doctools::MapFile --*/
01095 /* */
01096 /*  API for formatter. Maps symbolic to actual filename in a doctools*/
01097 /*  item. If no mapping is found it is assumed that the symbolic name*/
01098 /*  is also the actual name.*/
01099 /* */
01100 /*  Arguments:*/
01101 /*  name    Name of the doctools object to query.*/
01102 /*  fname   Symbolic name of the file.*/
01103 /* */
01104 /*  Results:*/
01105 /*  Actual name of the file.*/
01106 
01107 ret  ::doctools::MapFile (type name , type fname) {
01108     upvar ::doctools::doctools${name}::map map
01109 
01110     #parray map
01111 
01112     if {[info exists map($fname)]} {
01113     return $map($fname)
01114     }
01115     return $fname
01116 }
01117 
01118 /*  ::doctools::Source --*/
01119 /* */
01120 /*  API for formatter. Used by engine to ask for*/
01121 /*  additional script files support it.*/
01122 /* */
01123 /*  Arguments:*/
01124 /*  name    Name of the doctools object to change.*/
01125 /* */
01126 /*  Results:*/
01127 /*  Boolean flag.*/
01128 
01129 ret  ::doctools::Source (type ip , type path , type file) {
01130     #puts stderr "$ip (source $path $file)"
01131 
01132     $ip invokehidden source [file join $path [file tail $file]]
01133     #$ip eval [list source [file join $path [file tail $file]]]
01134     return
01135 }
01136 
01137 
01138 ret  ::doctools::Locate (type p) {
01139     # @mdgen NODEP: doctools::__undefined__
01140     catch {package require doctools::__undefined__}
01141 
01142     #puts stderr "auto_path = [join $::auto_path \n]"
01143 
01144     # Check if requested package is in the list of loadable packages.
01145     # Then get the highest possible version, and then the index script
01146 
01147     if {[lsearch -exact [package names] $p] < 0} {
01148     return -code error "Unknown package $p"
01149     }
01150 
01151     set v  [lindex [lsort -increasing [package versions $p]] end]
01152 
01153     #puts stderr "Package $p = $v"
01154 
01155     return [package ifneeded $p $v]
01156 }
01157 
01158 ret  ::doctools::FileOp (type ip , type args) {
01159     #puts stderr "$ip (file $args)"
01160     # -- FUTURE -- disallow unsafe operations --
01161 
01162     return [eval [linsert $args 0 file]]
01163 }
01164 
01165 
01166 ret  ::doctools::Package (type ip , type pkg) {
01167     #puts stderr "$ip package require $pkg"
01168 
01169     set indexScript [Locate $pkg]
01170 
01171     $ip expose source
01172     $ip expose load
01173     $ip eval        $indexScript
01174     $ip hide   source
01175     $ip hide   load
01176     #$ip eval [list source [file join $path [file tail $file]]]
01177     return
01178 }
01179 
01180 /* ------------------------------------*/
01181 /*  Module initialization*/
01182 
01183 namespace ::doctools {
01184     /*  Reverse order of searching. First to search is specified last.*/
01185 
01186     /*  FOO/doctools.tcl*/
01187     /*  => FOO/mpformats*/
01188 
01189     /* catch {search [file join $here                lib doctools mpformats]}*/
01190     /* catch {search [file join [file dirname $here] lib doctools mpformats]}*/
01191     catch {search [file join $here                             mpformats]}
01192 }
01193 
01194 package provide doctools 1.3
01195 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1