Index: openacs-4/packages/acs-api-browser/tcl/acs-api-documentation-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-api-browser/tcl/acs-api-documentation-procs.tcl,v
diff -u -r1.27 -r1.28
--- openacs-4/packages/acs-api-browser/tcl/acs-api-documentation-procs.tcl 7 Feb 2009 20:32:54 -0000 1.27
+++ openacs-4/packages/acs-api-browser/tcl/acs-api-documentation-procs.tcl 27 Oct 2014 16:38:59 -0000 1.28
@@ -1,5 +1,3 @@
-# /packages/acs-core/api-documentation-procs.tcl
-
ad_library {
Routines for generating API documentation.
@@ -11,152 +9,134 @@
}
-ad_proc -private api_first_sentence { string } {
+namespace eval ::apidoc {
- Returns the first sentence of a string.
+ if {[ns_info name] eq "NaviServer"} {
+ #
+ # NaviServer at sourceforge
+ #
+ set ns_api_host "http://naviserver.sourceforge.net/"
+ set ns_api_index "n/naviserver/files/"
+ set ns_api_root ${ns_api_host}${ns_api_index}
+ set ns_api_html_index $ns_api_root/commandlist.html
+ } else {
+ #
+ # AOLserver wiki on panpotic
+ #
+ set ns_api_host "http://panoptic.com/"
+ set ns_api_index "wiki/aolserver/Tcl_API"
+ set ns_api_root ${ns_api_host}${ns_api_index}
+ set ns_api_html_index $ns_api_root
+ }
-} {
+ set tcl_api_html_index "http://www.tcl.tk/man/tcl$::tcl_version/TclCmd/contents.htm"
- if { [regexp {^(.+?\.)\s} $string "" sentence] } {
- return $sentence
+ # set style {
+ # .code .comment {color: #006600; font-weight: normal; font-style: italic;}
+ # .code .keyword {color: #0000AA; font-weight: bold; font-style: normal;}
+ # .code .string {color: #990000; font-weight: normal; font-style: italic;}
+ # .code .var {color: #660066; font-weight: normal; font-style: normal;}
+ # .code .proc {color: #0000CC; font-weight: normal; font-style: normal;}
+ # .code .object {color: #000066; font-weight: bold; font-style: normal;}
+ # .code .helper {color: #0000CC; font-weight: bold; font-style: normal;}
+ # pre.code a {text-decoration: none;}
+ # }
+ set style {
+ .code .comment {color: #717ab3; font-weight: normal; font-style: italic;}
+ .code .keyword {color: #7f0055; font-weight: normal; font-style: normal;}
+ .code .string {color: #779977; font-weight: normal; font-style: italic;}
+ .code .var {color: #AF663F; font-weight: normal; font-style: normal;}
+ .code .proc {color: #0000CC; font-weight: normal; font-style: normal;}
+ .code .object {color: #000066; font-weight: bold; font-style: normal;}
+ .code .helper {color: #aaaacc; font-weight: bold; font-style: normal;}
+ pre.code {
+ background: #fefefa;
+ border-color: #aaaaaa;
+ border-style: solid;
+ border-width: 1px;
+ /*width: 900px; overflow: auto;*/
+ }
+ pre.code a {text-decoration: none;}
}
- return $string
+
+ set KEYWORDS {
+
+ after append apply array bgerror binary break catch cd chan
+ clock close concat continue default dict encoding eof error
+ eval exec expr fblocked fconfigure fcopy file fileevent flush
+ for foreach format gets glob global if incr info interp join
+ lappend lassign lindex linsert list llength load lrange
+ lreplace lreverse lsearch lset lsort namespace open package
+ pid proc puts pwd read refchan regexp regsub rename return
+ scan seek set socket source split string subst switch tell
+ time trace unload unset update uplevel upvar variable vwait
+ while
+
+ }
+
}
+
ad_proc -public api_read_script_documentation {
path
} {
Reads the contract from a Tcl content page.
@param path the path of the Tcl file to examine, relative to the
- OpenACS root directory.
+ OpenACS root directory.
@return a list representation of the documentation element array, or
- an empty list if the file does not contain a doc_page_contract
- block.
+ an empty list if the file does not contain a doc_page_contract
+ block.
@error if the file does not exist.
} {
# First, examine the file to determine whether the first non-comment
# line begins with the string "ad_page_contract".
set has_contract_p 0
- if { ![file exists "[acs_root_dir]/$path"] } {
- return -code error "File $path does not exist"
+ if { ![file exists "$::acs::rootdir/$path"] } {
+ return -code error "File $path does not exist"
}
- set file [open "[acs_root_dir]/$path" "r"]
+ set file [open "$::acs::rootdir/$path" "r"]
while { [gets $file line] >= 0 } {
- # Eliminate any comment characters.
- regsub -all {#.*$} $line "" line
- set line [string trim $line]
- if { $line ne "" } {
- set has_contract_p [regexp {^ad_page_contract\s} $line]
- break
- }
+ # Eliminate any comment characters.
+ regsub -all {\#.*$} $line "" line
+ set line [string trim $line]
+ if { $line ne "" } {
+ set has_contract_p [regexp {(^ad_page_contract\s)|( initialize )} $line match]
+ break
+ }
}
close $file
if { !$has_contract_p } {
- return [list]
+ return [list]
}
doc_set_page_documentation_mode 1
- set errno [catch { source "[acs_root_dir]/$path" } error]
+ #ns_log notice "Sourcing $::acs::rootdir/$path in documentation mode"
+ set errno [catch { source "$::acs::rootdir/$path" } error]
doc_set_page_documentation_mode 0
- if { $errno == 1 } {
- global errorInfo
- if { [regexp {^ad_page_contract documentation} $errorInfo] } {
- array set doc_elements $error
- }
- } else {
- global errorCode
- global errorInfo
- return -code $errno -errorcode $errorCode -errorinfo $errorInfo $error
- }
-
- if { [info exists doc_elements] } {
- return [array get doc_elements]
- }
- return [list]
-}
-ad_proc -private api_format_see_list { sees } {
- Generate an HTML list of referenced procs and pages.
-} {
- append out "
See Also:\n
"
- foreach see $sees {
- append out "- [api_format_see $see]\n"
+ #
+ # In documentation mode, we expect ad_page_contract (and counterparts)
+ # to break out of sourcing with an error to avoid side-effects of sourcing
+ #
+ if { $errno == 1} {
+ if {[regexp {^ad_page_contract documentation} $::errorInfo] } {
+ array set doc_elements $error
+ }
+ if { [info exists doc_elements] } {
+ return [array get doc_elements]
+ }
+ return [list]
}
- append out "
\n"
-
- return $out
-}
-
-ad_proc -private api_format_author_list { authors } {
- Generates an HTML-formatted list of authors (including <dt>
and
- <dd>
tags).
-
- @param authors the list of author strings.
- @return the formatted list, or an empty string if there are no authors.
-
-} {
- if { [llength $authors] == 0 } {
- return ""
- }
- append out "Author[ad_decode [llength $authors] 1 "" "s"]:\n"
- foreach author $authors {
- append out "[api_format_author $author]\n"
- }
- return $out
+ return -code $errno -errorcode $::errorCode -errorinfo $::errorInfo $error
}
-
-ad_proc -private api_format_changelog_change { change } {
- Formats the change log line: turns email addresses in parenthesis into links.
-} {
- regsub {\(([^ \n\r\t]+@[^ \n\r\t]+\.[^ \n\r\t]+)\)} $change {(\1)} change
- return $change
-}
-
-ad_proc -private api_format_changelog_list { changelog } {
- Format the change log info
-} {
- append out "Changelog:\n"
- foreach change $changelog {
- append out "[api_format_changelog_change $change]\n"
- }
- return $out
-}
-
-
-ad_proc -private api_format_common_elements { doc_elements_var } {
- upvar $doc_elements_var doc_elements
-
- set out ""
-
- if { [info exists doc_elements(author)] } {
- append out [api_format_author_list $doc_elements(author)]
- }
- if { [info exists doc_elements(creation-date)] } {
- append out "Created:\n[lindex $doc_elements(creation-date) 0]\n"
- }
- if { [info exists doc_elements(change-log)] } {
- append out [api_format_changelog_list $doc_elements(change-log)]
- }
- if { [info exists doc_elements(cvs-id)] } {
- append out "CVS ID:\n[ns_quotehtml [lindex $doc_elements(cvs-id) 0]]
\n"
- }
- if { [info exists doc_elements(see)] } {
- append out [api_format_see_list $doc_elements(see)]
- }
-
- return $out
-}
-
-
-
ad_proc -public api_script_documentation {
{ -format text/html }
path
@@ -166,9 +146,9 @@
to obtain the comment or contract at the beginning.
@param format the type of documentation to generate. Currently, only
- text/html
is supported.
+ text/html
is supported.
@param path the path of the Tcl file to examine, relative to the
- OpenACS root directory.
+ OpenACS root directory.
@return the formatted documentation string.
@error if the file does not exist.
@@ -178,142 +158,121 @@
# If it's not a Tcl file, we can't do a heck of a lot yet. Eventually
# we'll be able to handle ADPs, at least.
if {[file extension $path] eq ".xql"} {
- append out "DB Query file
\n"
- return $out
+ append out "DB Query file
\n"
+ return $out
} elseif { [file extension $path] ne ".tcl" } {
- append out "Delivered as [ns_guesstype $path]
\n"
- return $out
+ set mime_type [ns_guesstype $path]
+ if {[string match image/* $mime_type] && [regexp {packages/(.*)/www/resources/(.*)$} $path . pkg name]} {
+ set preview ""
+ } else {
+ set preview ""
+ }
+ append out "
Delivered as $mime_type$preview
\n"
+ return $out
}
if { [catch { array set doc_elements [api_read_script_documentation $path] } error] } {
- append out "Unable to read $path: [ns_quotehtml $error]
\n"
- return $out
+ append out "Unable to read $path: [ns_quotehtml $error]
\n"
+ return $out
}
array set params [list]
if { [info exists doc_elements(param)] } {
- foreach param $doc_elements(param) {
- if { [regexp {^([^ \t]+)[ \t](.+)$} $param "" name value] } {
- set params($name) $value
- }
- }
+ foreach param $doc_elements(param) {
+ if { [regexp {^([^ \t]+)[ \t](.+)$} $param "" name value] } {
+ set params($name) $value
+ }
+ }
}
-
+
append out ""
if { [info exists doc_elements(main)] } {
- append out [lindex $doc_elements(main) 0]
+ append out [lindex $doc_elements(main) 0]
} else {
- append out "Does not contain a contract."
+ append out "Does not contain a contract."
}
append out "\n"
# XXX: This does not work at the moment. -bmq
-# if { [array size doc_elements] > 0 } {
-# array set as_flags $doc_elements(as_flags)
-# array set as_filters $doc_elements(as_filters)
-# array set as_default_value $doc_elements(as_default_value)
+ # if { [array size doc_elements] > 0 } {
+ # array set as_flags $doc_elements(as_flags)
+ # array set as_filters $doc_elements(as_filters)
+ # array set as_default_value $doc_elements(as_default_value)
-# if { [llength $doc_elements(as_arg_names)] > 0 } {
-# append out "- Query Parameters:
- \n"
-# foreach arg_name $doc_elements(as_arg_names) {
-# append out "$arg_name"
-# set notes [list]
-# if { [info exists as_default_value($arg_name)] } {
-# lappend notes "defaults to
\"$as_default_value($arg_name)\"
"
-# }
-# set notes [concat $notes $as_flags($arg_name)]
-# foreach filter $as_filters($arg_name) {
-# set filter_proc [ad_page_contract_filter_proc $filter]
-# lappend notes "$filter"
-# }
-# if { [llength $notes] > 0 } {
-# append out " ([join $notes ", "])"
-# }
-# if { [info exists params($arg_name)] } {
-# append out " - $params($arg_name)"
-# }
-# append out "
\n"
-# }
-# append out " \n"
-# }
-# if { [info exists doc_elements(type)] && $doc_elements(type) ne "" } {
-# append out "- Returns Type:
- $doc_elements(type)\n"
-# }
-# # XXX: Need to support "Returns Properties:"
-# }
+ # if { [llength $doc_elements(as_arg_names)] > 0 } {
+ # append out "
- Query Parameters:
- \n"
+ # foreach arg_name $doc_elements(as_arg_names) {
+ # append out "$arg_name"
+ # set notes [list]
+ # if { [info exists as_default_value($arg_name)] } {
+ # lappend notes "defaults to
\"$as_default_value($arg_name)\"
"
+ # }
+ # set notes [concat $notes $as_flags($arg_name)]
+ # foreach filter $as_filters($arg_name) {
+ # set filter_proc [ad_page_contract_filter_proc $filter]
+ # lappend notes "$filter"
+ # }
+ # if { [llength $notes] > 0 } {
+ # append out " ([join $notes ", "])"
+ # }
+ # if { [info exists params($arg_name)] } {
+ # append out " - $params($arg_name)"
+ # }
+ # append out "
\n"
+ # }
+ # append out " \n"
+ # }
+ # if { [info exists doc_elements(type)] && $doc_elements(type) ne "" } {
+ # append out "- Returns Type:
- $doc_elements(type)\n"
+ # }
+ # # XXX: Need to support "Returns Properties:"
+ # }
append out "
- Location:
- $path\n"
- append out [api_format_common_elements doc_elements]
+ append out [::apidoc::format_common_elements doc_elements]
append out "
"
return $out
}
-ad_proc -private api_format_author { author_string } {
- if { [regexp {^[^ \n\r\t]+$} $author_string] && \
- [string first "@" $author_string] >= 0 && \
- [string first ":" $author_string] < 0 } {
- return "$author_string"
- } elseif { [regexp {^([^\(\)]+)\s+\((.+)\)$} [string trim $author_string] {} name email] } {
- return "$name <$email>"
- }
- return $author_string
-}
-
-ad_proc -private api_format_see { see } {
- regsub -all {proc *} $see {} see
- set see [string trim $see]
- if {[nsv_exists api_proc_doc $see]} {
- return "$see"
- }
- if {[string match "/doc/*.html" $see]
- || [util_url_valid_p $see]} {
- return "$see"
- }
- if {[file exists "[get_server_root]${see}"]} {
- return "$see"
- }
- return ${see}
-}
-
ad_proc -public api_library_documentation {
{ -format text/html }
path
} {
Generates formatted documentation for a Tcl library file (just the header,
- describing what the library does).
+ describing what the library does).
@param path the path to the file, relative to the OpenACS path root.
} {
if { $format ne "text/html" } {
- return -code error "Only text/html documentation is currently supported"
+ return -code error "Only text/html documentation is currently supported"
}
set out "[file tail $path]
"
if { [nsv_exists api_library_doc $path] } {
- array set doc_elements [nsv_get api_library_doc $path]
- append out "\n"
- append out [lindex $doc_elements(main) 0]
+ array set doc_elements [nsv_get api_library_doc $path]
+ append out "\n"
+ append out [lindex $doc_elements(main) 0]
- append out "\n"
- append out "- Location:\n
- $path\n"
- if { [info exists doc_elements(creation-date)] } {
- append out "
- Created:\n
- [lindex $doc_elements(creation-date) 0]\n"
- }
- if { [info exists doc_elements(author)] } {
- append out "
- Author[ad_decode [llength $doc_elements(author)] 1 "" "s"]:\n"
- foreach author $doc_elements(author) {
- append out "
- [api_format_author $author]\n"
- }
- }
- if { [info exists doc_elements(cvs-id)] } {
- append out "
- CVS Identification:\n
[ns_quotehtml [lindex $doc_elements(cvs-id) 0]]
\n"
- }
- append out "
\n"
- append out "
\n"
+ append out "\n"
+ append out "- Location:\n
- $path\n"
+ if { [info exists doc_elements(creation-date)] } {
+ append out "
- Created:\n
- [lindex $doc_elements(creation-date) 0]\n"
+ }
+ if { [info exists doc_elements(author)] } {
+ append out "
- Author[ad_decode [llength $doc_elements(author)] 1 "" "s"]:\n"
+ foreach author $doc_elements(author) {
+ append out "
- [::apidoc::format_author $author]\n"
+ }
+ }
+ if { [info exists doc_elements(cvs-id)] } {
+ append out "
- CVS Identification:\n
[ns_quotehtml [lindex $doc_elements(cvs-id) 0]]
\n"
+ }
+ append out "
\n"
+ append out "
\n"
}
return $out
@@ -338,340 +297,319 @@
array set property_doc [list]
if { [info exists doc_elements(property)] } {
- foreach property $doc_elements(property) {
- if { [regexp {^([^ \t]+)[ \t](.+)$} $property "" name value] } {
- set property_doc($name) $value
- }
- }
+ foreach property $doc_elements(property) {
+ if { [regexp {^([^ \t]+)[ \t](.+)$} $property "" name value] } {
+ set property_doc($name) $value
+ }
+ }
}
foreach property [lsort [array names properties]] {
- set info $properties($property)
- set type [lindex $info 0]
- append out "$property"
- if { $type ne "onevalue" } {
- append out " ($type)"
- }
- if { [info exists property_doc($property)] } {
- append out " - $property_doc($property)"
- }
- if {$type eq "onerow"} {
- append out "
\n"
- } else {
- set columns [lindex $info 1]
- append out "\n"
- foreach column $columns {
- append out "- $column"
- if { [info exists property_doc($property.$column)] } {
- append out " - $property_doc($property.$column)"
- }
- }
- append out "
\n"
- }
+ set info $properties($property)
+ set type [lindex $info 0]
+ append out "$property"
+ if { $type ne "onevalue" } {
+ append out " ($type)"
+ }
+ if { [info exists property_doc($property)] } {
+ append out " - $property_doc($property)"
+ }
+ if {$type eq "onerow"} {
+ append out "
\n"
+ } else {
+ set columns [lindex $info 1]
+ append out "\n"
+ foreach column $columns {
+ append out "- $column"
+ if { [info exists property_doc($property.$column)] } {
+ append out " - $property_doc($property.$column)"
+ }
+ }
+ append out "
\n"
+ }
}
- append out [api_format_common_elements doc_elements]
+ append out \
+ [::apidoc::format_common_elements doc_elements] \
+ "Location:$doc_elements(script)\n" \
+ "\n"
- append out "Location:$doc_elements(script)\n"
-
- append out "\n"
-
return $out
}
-ad_proc -private api_set_public {
- version_id
- { public_p "" }
+ad_proc -public api_proc_documentation {
+ {-format text/html}
+ -script:boolean
+ -source:boolean
+ -xql:boolean
+ -label
+ {-first_line_tag }
+ proc_name
} {
-
- Gets or sets the user's public/private preferences for a given
- package.
- @param version_id the version of the package
- @param public_p if empty, return the user's preferred setting or the default (1) if no preference found. If not empty, set the user's preference to public_p
- @return public_p
+ Generates formatted documentation for a procedure.
+ @param format the type of documentation to generate. Currently, only
+ text/html
and text/plain
are supported.
+ @param script include information about what script this proc lives in?
+ @param xql include the source code for the related xql files?
+ @param source include the source code for the script?
+ @param proc_name the name of the procedure for which to generate documentation.
+ @param label the label printed for the proc in the header line
+ @param first_line_tag tag for the markup of the first line
+ @return the formatted documentation string.
+ @error if the procedure is not defined.
} {
- set public_property_name "api,package,$version_id,public_p"
- if { $public_p eq "" } {
- set public_p [ad_get_client_property acs-api-browser $public_property_name]
- if { $public_p eq "" } {
- set public_p 1
- }
+ if { $format ne "text/html" && $format ne "text/plain" } {
+ return -code error "Only text/html and text/plain documentation are currently supported"
+ }
+ array set doc_elements [nsv_get api_proc_doc $proc_name]
+ array set flags $doc_elements(flags)
+ array set default_values $doc_elements(default_values)
+
+ if {![info exists label]} {
+ set label $proc_name
+ }
+ if { $script_p } {
+ set pretty_name [api_proc_pretty_name -label $label $proc_name]
} else {
- ad_set_client_property acs-api-browser $public_property_name $public_p
+ set pretty_name [api_proc_pretty_name -link -label $label $proc_name]
}
- return $public_p
-}
+ if {[regexp {<([^ >]+)} $first_line_tag match tag]} {
+ set end_tag "$tag>"
+ } else {
+ set first_line_tag ""
+ set end_tag "
"
+ }
+ append out $first_line_tag$pretty_name$end_tag
+
+ if {[regexp {^(.*) (inst)?proc (.*)$} $proc_name match cl prefix method]} {
+ set xotcl 1
+ set scope ""
+ if {[regexp {^(.+) (.+)$} $cl match scope cl]} {
+ set cl "$scope do $cl"
+ }
+ if {$prefix eq ""} {
+ set pretty_proc_name "[::xotcl::api object_link $scope $cl] $method"
+ } else {
+ set pretty_proc_name \
+ "<instance of\
+ [::xotcl::api object_link $scope $cl]> $method"
+ }
+ } else {
+ set xotcl 0
+ set pretty_proc_name $proc_name
+ }
-ad_proc -public api_quote_file {
- filename
-} {
- returns a quoted version of the given filename
-} {
- if {![catch {set fp [open $filename r]} err]} {
- set content [ad_quotehtml [read $fp]]
- close $fp
- return $content
- }
- return {}
-}
-
-
-ad_proc -public api_proc_documentation {
- {-format text/html}
- -script:boolean
- -source:boolean
- -xql:boolean
- -label
- {-first_line_tag }
- proc_name
-} {
-
- Generates formatted documentation for a procedure.
-
- @param format the type of documentation to generate. Currently, only
- text/html
and text/plain
are supported.
- @param script include information about what script this proc lives in?
- @param xql include the source code for the related xql files?
- @param source include the source code for the script?
- @param proc_name the name of the procedure for which to generate documentation.
- @param label the label printed for the proc in the header line
- @param first_line_tag tag for the markup of the first line
- @return the formatted documentation string.
- @error if the procedure is not defined.
-} {
- if { $format ne "text/html" && \
- $format ne "text/plain" } {
- return -code error "Only text/html and text/plain documentation are currently supported"
- }
- array set doc_elements [nsv_get api_proc_doc $proc_name]
- array set flags $doc_elements(flags)
- array set default_values $doc_elements(default_values)
-
- if {![info exists label]} {
- set label $proc_name
+ lappend command_line $pretty_proc_name
+ foreach switch $doc_elements(switches) {
+ if {$xotcl} {
+ if {"boolean" in $flags($switch)} {
+ set value "on|off "
+ } elseif {"switch" in $flags($switch)} {
+ set value ""
+ } else {
+ set value "$switch "
+ }
+ if {"required" in $flags($switch)} {
+ lappend command_line "-$switch $value"
+ } else {
+ lappend command_line "\[ -$switch $value\]"
+ }
+ } else {
+ if {"boolean" in $flags($switch)} {
+ lappend command_line "\[ -$switch \]"
+ } elseif {"required" in $flags($switch)} {
+ lappend command_line "-$switch $switch"
+ } else {
+ lappend command_line "\[ -$switch $switch \]"
+ }
}
- if { $script_p } {
- set pretty_name [api_proc_pretty_name -label $label $proc_name]
- } else {
- set pretty_name [api_proc_pretty_name -link -label $label $proc_name]
- }
- if {[regexp {<([^ >]+)} $first_line_tag match tag]} {
- set end_tag "$tag>"
- } else {
- set first_line_tag ""
- set end_tag "
"
- }
- append out $first_line_tag$pretty_name$end_tag
-
- if {[regexp {^(.*) (inst)?proc (.*)$} $proc_name match cl prefix method]} {
- set xotcl 1
- set scope ""
- if {[regexp {^(.+) (.+)$} $cl match scope cl]} {
- set cl "$scope do $cl"
- }
- if {$prefix eq ""} {
- set pretty_proc_name "[::xotcl::api object_link $scope $cl] $method"
- } else {
- set pretty_proc_name \
- "<instance of\
- [::xotcl::api object_link $scope $cl]> $method"
- }
- } else {
- set xotcl 0
- set pretty_proc_name $proc_name
- }
+ }
+
+ set counter 0
+ foreach positional $doc_elements(positionals) {
+ if { [info exists default_values($positional)] } {
+ lappend command_line "\[ $positional \]"
+ } else {
+ lappend command_line "$positional"
+ }
+ }
+ if { $doc_elements(varargs_p) } {
+ lappend command_line "\[ args... \]"
+ }
+ append out [util_wrap_list $command_line] "\n\n"
+
+ if { $script_p } {
+ append out [subst {Defined in
+ $doc_elements(script)
+ }]
+ }
+
+ if { $doc_elements(deprecated_p) } {
+ append out "Deprecated."
+ if { $doc_elements(warn_p) } {
+ append out " Invoking this procedure generates a warning."
+ }
+ append out "
\n"
+ }
- lappend command_line $pretty_proc_name
- foreach switch $doc_elements(switches) {
- if {$xotcl} {
- if { [lsearch $flags($switch) "boolean"] >= 0} {
- set value "on|off "
- } elseif { [lsearch $flags($switch) "switch"] >= 0} {
- set value ""
- } else {
- set value "$switch "
- }
- if { [lsearch $flags($switch) "required"] >= 0} {
- lappend command_line "-$switch $value"
- } else {
- lappend command_line "\[ -$switch $value\]"
- }
- } else {
- if { [lsearch $flags($switch) "boolean"] >= 0} {
- lappend command_line "\[ -$switch \]"
- } elseif { [lsearch $flags($switch) "required"] >= 0 } {
- lappend command_line "-$switch $switch"
- } else {
- lappend command_line "\[ -$switch $switch \]"
- }
- }
- }
-
- set counter 0
- foreach positional $doc_elements(positionals) {
- if { [info exists default_values($positional)] } {
- lappend command_line "\[ $positional \]"
- } else {
- lappend command_line "$positional"
- }
- }
- if { $doc_elements(varargs_p) } {
- lappend command_line "\[ args... \]"
- }
- append out "[util_wrap_list $command_line]\n
\n"
-
- if { $script_p } {
- append out "Defined in $doc_elements(script)"
- }
-
- if { $doc_elements(deprecated_p) } {
- append out "Deprecated."
- if { $doc_elements(warn_p) } {
- append out " Invoking this procedure generates a warning."
- }
- append out "
\n"
- }
+ append out "[lindex $doc_elements(main) 0]\n
\n
\n"
- append out "[lindex $doc_elements(main) 0]
-
-
-
-"
-
- if { [info exists doc_elements(param)] } {
- foreach param $doc_elements(param) {
- if { [regexp {^([^ \t\n]+)[ \t\n]+(.*)$} $param "" name value] } {
- set params($name) $value
+ if { [info exists doc_elements(param)] } {
+ foreach param $doc_elements(param) {
+ if { [regexp {^([^ \t\n]+)[ \t\n]+(.*)$} $param "" name value] } {
+ set params($name) $value
+ }
+ }
+ }
+
+ if { [llength $doc_elements(switches)] > 0 } {
+ append out "- Switches:
\n"
+ foreach switch $doc_elements(switches) {
+ append out "- -$switch"
+ if {"boolean" in $flags($switch)} {
+ append out " (boolean)"
+ }
+
+ if { [info exists default_values($switch)]
+ && $default_values($switch) ne ""
+ } {
+ append out " (defaults to
\"[ns_quotehtml $default_values($switch)]\"
)"
+ }
+
+ if {"required" in $flags($switch)} {
+ append out " (required)"
+ } else {
+ append out " (optional)"
+ }
+ append out " "
+ if { [info exists params($switch)] } {
+ append out "- $params($switch)
"
+ }
+ }
+ append out "
\n"
+ }
+
+ if { [llength $doc_elements(positionals)] > 0 } {
+ append out "- Parameters:
- \n"
+ foreach positional $doc_elements(positionals) {
+ append out "$positional"
+ if { [info exists default_values($positional)] } {
+ if { $default_values($positional) eq "" } {
+ append out " (optional)"
+ } else {
+ append out " (defaults to
\"$default_values($positional)\"
)"
}
}
- }
-
- if { [llength $doc_elements(switches)] > 0 } {
- append out " - Switches:
\n"
- foreach switch $doc_elements(switches) {
- append out "- -$switch"
- if { [lsearch $flags($switch) "boolean"] >= 0 } {
- append out " (boolean)"
- }
-
- if { [info exists default_values($switch)] && \
- $default_values($switch) ne "" } {
- append out " (defaults to
\"$default_values($switch)\"
)"
- }
-
- if { [lsearch $flags($switch) "required"] >= 0 } {
- append out " (required)"
- } else {
- append out " (optional)"
- }
- append out " "
- if { [info exists params($switch)] } {
- append out "- $params($switch)
"
- }
- }
- append out "
\n"
- }
-
- if { [llength $doc_elements(positionals)] > 0 } {
- append out "- Parameters:
- \n"
- foreach positional $doc_elements(positionals) {
- append out "$positional"
- if { [info exists default_values($positional)] } {
- if { $default_values($positional) eq "" } {
- append out " (optional)"
- } else {
- append out " (defaults to
\"$default_values($positional)\"
)"
- }
- }
- if { [info exists params($positional)] } {
- append out " - $params($positional)"
- }
- append out "
\n"
- }
- append out " \n"
- }
-
+ if { [info exists params($positional)] } {
+ append out " - $params($positional)"
+ }
+ append out "
\n"
+ }
+ append out "
\n"
+ }
+
- # @option is used in template:: and cms:: (and maybe should be used in some other
- # things like ad_form which have internal arg parsers. although an option
- # and a switch are the same thing, just one is parsed in the proc itself rather than
- # by ad_proc.
+ # @option is used in template:: and cms:: (and maybe should be used in some other
+ # things like ad_form which have internal arg parsers. although an option
+ # and a switch are the same thing, just one is parsed in the proc itself rather than
+ # by ad_proc.
- if { [info exists doc_elements(option)] } {
- append out "Options:"
- foreach param $doc_elements(option) {
- if { [regexp {^([^ \t]+)[ \t](.+)$} $param "" name value] } {
- append out "- -$name
- $value
"
- }
- }
- append out "
"
- }
-
+ if { [info exists doc_elements(option)] } {
+ append out "Options:"
+ foreach param $doc_elements(option) {
+ if { [regexp {^([^ \t]+)[ \t](.+)$} $param "" name value] } {
+ append out "- -$name
- $value
"
+ }
+ }
+ append out "
"
+ }
+
- if { [info exists doc_elements(return)] } {
- append out "Returns:[join $doc_elements(return) "
"]\n"
- }
-
- if { [info exists doc_elements(error)] } {
- append out "Error:[join $doc_elements(error) "
"]\n"
- }
-
- append out [api_format_common_elements doc_elements]
-
- if { $source_p } {
- if {[parameter::get_from_package_key \
- -package_key acs-api-browser \
- -parameter FancySourceFormattingP \
- -default 1]} {
- append out "Source code:
-[api_tcl_to_html $proc_name]
-
\n"
- } else {
- append out "
Source code:
-[ns_quotehtml [api_get_body $proc_name]]
-
\n"
- }
+ if { [info exists doc_elements(return)] } {
+ append out "
Returns:[join $doc_elements(return) "
"]\n"
+ }
+
+ if { [info exists doc_elements(error)] } {
+ append out "Error:[join $doc_elements(error) "
"]\n"
+ }
+
+ append out [::apidoc::format_common_elements doc_elements]
+
+ if { $source_p } {
+ if {[parameter::get_from_package_key \
+ -package_key acs-api-browser \
+ -parameter FancySourceFormattingP \
+ -default 1]} {
+ append out [subst {Source code:
+ [::apidoc::tcl_to_html $proc_name]
+
+ }]
+ } else {
+ append out [subst {
Source code:
+ [ns_quotehtml [api_get_body $proc_name]]
+
+ }]
}
+ }
- set xql_base_name [get_server_root]/
- append xql_base_name [file rootname $doc_elements(script)]
- if { $xql_p } {
- set there {}
- set missing {}
- if { [file exists ${xql_base_name}.xql] } {
- append there "
Generic XQL file:
-[api_quote_file ${xql_base_name}.xql]
-\n"
- } else {
- lappend missing Generic
- }
- if { [file exists ${xql_base_name}-postgresql.xql] } {
- append there "
Postgresql XQL file:
-[api_quote_file ${xql_base_name}-postgresql.xql]
-\n"
- } else {
- lappend missing PostgreSQL
- }
- if { [file exists ${xql_base_name}-oracle.xql] } {
- append there "
Oracle XQL file:
-[api_quote_file ${xql_base_name}-oracle.xql]
-\n"
- } else {
- lappend missing Oracle
- }
- if {[llength $missing] > 0} {
- append out "
XQL Not present:[join $missing ", "]"
- }
- append out $there
- }
+ set xql_base_name $::acs::rootdir/
+ append xql_base_name [file rootname $doc_elements(script)]
+ if { $xql_p } {
+ set there {}
+ set missing {}
+ set xql_fn [file rootname $doc_elements(script)].xql
+ if { [file exists $::acs::rootdir/$xql_fn] } {
+ set content [apidoc::get_xql_snippet -proc_name $proc_name -xql_file $xql_fn]
+ if {$content ne ""} {set content "$content
"}
+ append there [subst {Generic XQL file:
+ $content
+ $xql_fn
+
+
+ }]
+ } else {
+ lappend missing Generic
+ }
+ set xql_fn [file rootname $doc_elements(script)]-postgresql.xql
+ if { [file exists $::acs::rootdir/$xql_fn] } {
+ set content [apidoc::get_xql_snippet -proc_name $proc_name -xql_file $xql_fn]
+ if {$content ne ""} {set content "
$content
"}
+ append there [subst {PostgreSQL XQL file:
+ $content
+ $xql_fn
+
+
+ }]
+ } else {
+ lappend missing PostgreSQL
+ }
+ set xql_fn [file rootname $doc_elements(script)]-oracle.xql
- # No "see also" yet.
-
- append out ""
-
- return $out
+ if { [file exists $::acs::rootdir/$xql_fn] } {
+ set content [apidoc::get_xql_snippet -proc_name $proc_name -xql_file $xql_fn]
+ if {$content ne ""} {set content "
$content
"}
+ append there [subst {Oracle XQL file:
+ $content
+ $xql_fn
+
+
+ }]
+ } else {
+ lappend missing Oracle
+ }
+ if {[llength $missing] > 0} {
+ append out [subst {
XQL Not present:[join $missing ", "]}]
+ }
+ append out $there
+ }
+
+ # No "see also" yet.
+
+ append out ""
+
+ return $out
}
ad_proc api_proc_pretty_name {
@@ -680,92 +618,41 @@
proc
} {
Return a pretty version of a proc name
- @param label the label printed for the proc in the header line
- @param link provide a link to the documentation pages
+ @param label the label printed for the proc in the header line
+ @param link provide a link to the documentation pages
} {
if {![info exists label]} {
set label $proc
}
if { $link_p } {
- append out "$label"
- } else {
- append out "$label"
+ append out "$label"
+ } else {
+ append out "$label"
}
array set doc_elements [nsv_get api_proc_doc $proc]
+ if {$doc_elements(deprecated_p)} {
+ set deprecated ", decprecated"
+ } else {
+ set deprecated ""
+ }
if { $doc_elements(public_p) } {
- append out " (public)"
+ append out " (public$deprecated)"
}
if { $doc_elements(private_p) } {
- append out " (private)"
+ append out " (private$deprecated)"
}
return $out
}
-ad_proc -private ad_sort_by_score_proc {l1 l2} {
- basically a -1,0,1 result comparing the second element of the
- list inputs then the first. (second is int)
-} {
- if {[lindex $l1 1] == [lindex $l2 1]} {
- return [string compare [lindex $l1 0] [lindex $l2 0]]
- } else {
- if {[lindex $l1 1] > [lindex $l2 1]} {
- return -1
- } else {
- return 1
- }
- }
-}
-
-ad_proc -private ad_sort_by_second_string_proc {l1 l2} {
- basically a -1,0,1 result comparing the second element of the
- list inputs then the first (both strings)
-} {
- if {[lindex $l1 1] eq [lindex $l2 1]} {
- return [string compare [lindex $l1 0] [lindex $l2 0]]
- } else {
- return [string compare [lindex $l1 1] [lindex $l2 1]]
- }
-}
-
-ad_proc -private ad_sort_by_first_string_proc {l1 l2} {
- basically a -1,0,1 result comparing the second element of the
- list inputs then the first. (both strings)
-} {
- if {[lindex $l1 0] eq [lindex $l2 0]} {
- return [string compare [lindex $l1 1] [lindex $l2 1]]
- } else {
- return [string compare [lindex $l1 0] [lindex $l2 0]]
- }
-}
-
-ad_proc -private ad_keywords_score {keywords string_to_search} {
- returns number of keywords found in string to search.
- No additional score for repeats
-} {
- # turn keywords into space-separated things
- # replace one or more commads with a space
- regsub -all {,+} $keywords " " keywords
-
- set score 0
- foreach word $keywords {
- # turns out that "" is never found in a search, so we
- # don't really have to special case $word eq ""
- if {[string match -nocase "*$word*" $string_to_search]} {
- incr score
- }
- }
- return $score
-}
-
ad_proc -public api_apropos_functions { string } {
Returns the functions in the system that contain string in their name
and have been defined using ad_proc.
} {
set matches [list]
foreach function [nsv_array names api_proc_doc] {
- if {[string match -nocase *$string* $function]} {
+ if {[string match -nocase "*$string*" $function]} {
array set doc_elements [nsv_get api_proc_doc $function]
- lappend matches [list "$function" "$doc_elements(positionals)"]
+ lappend matches [list $function $doc_elements(positionals)]
}
}
return $matches
@@ -804,93 +691,303 @@
return $matches
}
-ad_proc -private api_is_xotcl_object {scope proc_name} {
- Checks, whether the specified argument is an xotcl object.
- Does not cause problems when xocl is not loaded.
- @return boolean value
-} {
- set result 0
- if {[string match "::*" $proc_name]} { ;# only check for absolute names
- catch {set result [::xotcl::api inscope $scope ::xotcl::Object isobject $proc_name]}
- }
- return $result
-}
ad_proc -public api_get_body {proc_name} {
- This function returns the body of a tcl proc or an xotcl method.
- @param proc_name the name spec of the proc
- @return body of the specified prox
+ This function returns the body of a tcl proc or an xotcl method.
+ @param proc_name the name spec of the proc
+ @return body of the specified prox
} {
- if {[regexp {^(.*) (inst)?proc (.*)$} $proc_name match obj prefix method]} {
- if {[regexp {^(.*) (.*)$} $obj match thread obj]} {
- # the definition is located in a disconnected thread
- return [$thread do ::Serializer methodSerialize $obj $method $prefix]
+ if {[regexp {^(.*) (inst)?proc (.*)$} $proc_name match obj prefix method]} {
+ if {[regexp {^(.*) (.*)$} $obj match thread obj]} {
+ # the definition is located in a disconnected thread
+ return [$thread do ::Serializer methodSerialize $obj $method $prefix]
+ } else {
+ # the definition is locally in the connection thread
+ return [::Serializer methodSerialize $obj $method $prefix]
+ }
+ } elseif {[regexp {^([^ ]+)(Class|Object) (.*)$} $proc_name match thread kind obj]} {
+ return [$thread do $obj serialize]
+ } elseif {[info procs $proc_name] ne ""} {
+ return [info body $proc_name]
+ } elseif {[info procs ::nsf::procs::$proc_name] ne ""} {
+ return [::nx::Object info method body ::nsf::procs::$proc_name]
} else {
- # the definition is locally in the connection thread
- return [::Serializer methodSerialize $obj $method $prefix]
+ return "No such Tcl-proc"
}
- } elseif {[regexp {^([^ ]+)(Class|Object) (.*)$} $proc_name match thread kind obj]} {
- return [$thread do $obj serialize]
- } else {
- return [info body $proc_name]
- }
}
-ad_proc -private api_tcl_to_html {proc_name} {
+namespace eval ::apidoc {
- Given a proc name, formats it as HTML, including highlighting syntax in
- various colors and creating hyperlinks to other proc definitions.
- The inspiration for this proc was the tcl2html script created by Jeff Hobbs.
-
- Known Issues:
-
-- This proc will mistakenly highlight switch strings that look like commands as commands, etc.
-
- There are many undocumented AOLserver commands including all of the commands added by modules.
-
- When a proc inside a string has explicitly quoted arguments, they are not formatted.
-
- regexp and regsub are hard to parse properly. E.g. If we use the start option, and we quote its argument,
- and we have an ugly regexp, then this code might highlight it incorrectly.
-
+ ad_proc -private get_xql_snippet {-proc_name -xql_file} {
+ @return matching xql snippet for specified proc_name
+ } {
+ set content [template::util::read_file $::acs::rootdir/$xql_file]
- @author Jamie Rasmussen (jrasmuss@mle.ie)
+ # make parsable XML, replace "partialquery" by "fullquery"
+ set prepared_content [db_qd_internal_prepare_queryfile_content $content]
- @param proc_name procedure to format in HTML
+ dom parse -simple $prepared_content doc
+ $doc documentElement root
+ set result ""
+ foreach q [$root selectNodes //fullquery] {
+ if {[string match "$proc_name.*" [$q getAttribute name]]} {
+ append result [$q asXML -indent 4] \n
+ }
+ }
+ set readable_xml [string map {< < > > & &} [string trimright $result]]
+ return [ns_quotehtml $readable_xml]
+ }
-} {
+ ad_proc -public format_see { see } {
+ regsub -all {proc *} $see {} see
+ set see [string trim $see]
+ if {[nsv_exists api_proc_doc $see]} {
+ return "$see"
+ }
+ if {[string match "/doc/*.html" $see]
+ || [util_url_valid_p $see]} {
+ return "$see"
+ }
+ if {[file exists "$::acs::rootdir${see}"]} {
+ return "$see"
+ }
+ return ${see}
+ }
- if {[info command ::xotcl::api] ne ""} {
- set scope [::xotcl::api scope_from_proc_index $proc_name]
- } else {
- set scope ""
+ ad_proc -public format_author { author_string } {
+ if { [regexp {^[^ \n\r\t]+$} $author_string]
+ && [string first "@" $author_string] >= 0
+ && [string first ":" $author_string] < 0 } {
+ return "$author_string"
+ } elseif { [regexp {^([^\(\)]+)\s+\((.+)\)$} [string trim $author_string] {} name email] } {
+ return "$name <$email>"
+ }
+ return $author_string
}
- set proc_namespace ""
- regexp {^(::)?(.*)::[^:]+$} $proc_name match colons proc_namespace
+ ad_proc -private format_changelog_list { changelog } {
+ Format the change log info
+ } {
+ append out "Changelog:\n"
+ foreach change $changelog {
+ append out "[format_changelog_change $change]\n"
+ }
+ return $out
+ }
- return [api_tclcode_to_html -scope $scope -proc_namespace $proc_namespace [api_get_body $proc_name]]
-}
+ ad_proc -private format_changelog_change { change } {
+ Formats the change log line: turns email addresses in parenthesis into links.
+ } {
+ regsub {\(([^ \n\r\t]+@[^ \n\r\t]+\.[^ \n\r\t]+)\)} $change {(\1)} change
+ return $change
+ }
-ad_proc -private api_tclcode_to_html {{-scope ""} {-proc_namespace ""} script} {
+ ad_proc -private format_author_list { authors } {
- Given a script, this proc formats it as HTML, including highlighting syntax in
- various colors and creating hyperlinks to other proc definitions.
- The inspiration for this proc was the tcl2html script created by Jeff Hobbs.
+ Generates an HTML-formatted list of authors
+ (including <dt>
and
+ <dd>
tags).
- @param script script to be formated in HTML
+ @param authors the list of author strings.
+ @return the formatted list, or an empty string if there are no authors.
-} {
+ } {
+ if { [llength $authors] == 0 } {
+ return ""
+ }
+ append out "Author[ad_decode [llength $authors] 1 "" "s"]:\n"
+ foreach author $authors {
+ append out "[format_author $author]\n"
+ }
+ return $out
+ }
+ ad_proc -private format_common_elements { doc_elements_var } {
+ upvar $doc_elements_var doc_elements
+
+ set out ""
+
+ if { [info exists doc_elements(author)] } {
+ append out [format_author_list $doc_elements(author)]
+ }
+ if { [info exists doc_elements(creation-date)] } {
+ append out "Created:\n[lindex $doc_elements(creation-date) 0]\n"
+ }
+ if { [info exists doc_elements(change-log)] } {
+ append out [format_changelog_list $doc_elements(change-log)]
+ }
+ if { [info exists doc_elements(cvs-id)] } {
+ append out "CVS ID:\n[ns_quotehtml [lindex $doc_elements(cvs-id) 0]]
\n"
+ }
+ if { [info exists doc_elements(see)] } {
+ append out [format_see_list $doc_elements(see)]
+ }
+
+ return $out
+ }
+
+ ad_proc -private format_see_list { sees } {
+ Generate an HTML list of referenced procs and pages.
+ } {
+ append out "
See Also:\n"
+ foreach see $sees {
+ append out "- [format_see $see]\n"
+ }
+ append out "
\n"
+
+ return $out
+ }
+
+ ad_proc -private first_sentence { string } {
+
+ Returns the first sentence of a string.
+
+ } {
+ if { [regexp {^(.+?\.)\s} $string "" sentence] } {
+ return $sentence
+ }
+ return $string
+ }
+
+ ad_proc -private set_public {
+ version_id
+ { public_p "" }
+ } {
+
+ Gets or sets the user's public/private preferences for a given
+ package.
+
+ @param version_id the version of the package
+ @param public_p if empty, return the user's preferred setting or the default (1)
+ if no preference found. If not empty, set the user's preference to public_p
+ @return public_p
+
+ } {
+ set public_property_name "api,package,$version_id,public_p"
+ if { $public_p eq "" } {
+ set public_p [ad_get_client_property acs-api-browser $public_property_name]
+ if { $public_p eq "" } {
+ set public_p 1
+ }
+ } else {
+ ad_set_client_property acs-api-browser $public_property_name $public_p
+ }
+ return $public_p
+ }
+
+ ad_proc -private ad_sort_by_score_proc {l1 l2} {
+ basically a -1,0,1 result comparing the second element of the
+ list inputs then the first. (second is int)
+ } {
+ if {[lindex $l1 1] eq [lindex $l2 1]} {
+ return [string compare [lindex $l1 0] [lindex $l2 0]]
+ } else {
+ if {[lindex $l1 1] > [lindex $l2 1]} {
+ return -1
+ } else {
+ return 1
+ }
+ }
+ }
+
+ ad_proc -private ad_sort_by_second_string_proc {l1 l2} {
+ basically a -1,0,1 result comparing the second element of the
+ list inputs then the first (both strings)
+ } {
+ if {[lindex $l1 1] eq [lindex $l2 1]} {
+ return [string compare [lindex $l1 0] [lindex $l2 0]]
+ } else {
+ return [string compare [lindex $l1 1] [lindex $l2 1]]
+ }
+ }
+
+ ad_proc -private ad_sort_by_first_string_proc {l1 l2} {
+ basically a -1,0,1 result comparing the second element of the
+ list inputs then the first. (both strings)
+ } {
+ if {[lindex $l1 0] eq [lindex $l2 0]} {
+ return [string compare [lindex $l1 1] [lindex $l2 1]]
+ } else {
+ return [string compare [lindex $l1 0] [lindex $l2 0]]
+ }
+ }
+
+ ad_proc -private ad_keywords_score {keywords string_to_search} {
+ returns number of keywords found in string to search.
+ No additional score for repeats
+ } {
+ # turn keywords into space-separated things
+ # replace one or more commads with a space
+ regsub -all {,+} $keywords " " keywords
+
+ set score 0
+ foreach word $keywords {
+ # turns out that "" is never found in a search, so we
+ # don't really have to special case $word eq ""
+ if {[string match -nocase "*$word*" $string_to_search]} {
+ incr score
+ }
+ }
+ return $score
+ }
+
+ ad_proc -private is_xotcl_object {scope proc_name} {
+ Checks, whether the specified argument is an xotcl object.
+ Does not cause problems when xocl is not loaded.
+ @return boolean value
+ } {
+ set result 0
+ catch {set result [::xotcl::api inscope $scope ::xotcl::Object isobject $proc_name]}
+ return $result
+ }
+
+ ad_proc -private tcl_to_html {proc_name} {
+
+ Given a proc name, formats it as HTML, including highlighting syntax in
+ various colors and creating hyperlinks to other proc definitions.
+ The inspiration for this proc was the tcl2html script created by Jeff Hobbs.
+
+ Known Issues:
+
+ - This proc will mistakenly highlight switch strings that look like commands as commands, etc.
+
- There are many undocumented AOLserver commands including all of the commands added by modules.
+
- When a proc inside a string has explicitly quoted arguments, they are not formatted.
+
- regexp and regsub are hard to parse properly. E.g. If we use the start option, and we quote its argument,
+ and we have an ugly regexp, then this code might highlight it incorrectly.
+
+
+ @author Jamie Rasmussen (jrasmuss@mle.ie)
+
+ @param proc_name procedure to format in HTML
+
+ } {
+
+ if {[info commands ::xotcl::api] ne ""} {
+ set scope [::xotcl::api scope_from_proc_index $proc_name]
+ } else {
+ set scope ""
+ }
+
+ set proc_namespace ""
+ regexp {^(::)?(.*)::[^:]+$} $proc_name match colons proc_namespace
+
+ return [tclcode_to_html -scope $scope -proc_namespace $proc_namespace [api_get_body $proc_name]]
+ }
+
+
# Returns length of a variable name
proc length_var {data} {
if {[regexp -indices {^\$\{[^\}]+\}} $data found]} {
return [lindex $found 1]
- } elseif {[regexp -indices {^\$[A-Za-z0-9_]+(\([\$A-Za-z0-9_\-/]+\))?} $data found]} {
+ } elseif {[regexp -indices {^\$[A-Za-z0-9_:]+(\([\$A-Za-z0-9_\-/]+\))?} $data found]} {
return [lindex $found 1]
}
return 0
}
+
# Returns length of a command name
proc length_proc {data} {
if {[regexp -indices {^(::)?[A-Za-z][:A-Za-z0-9_@]+} $data found]} {
@@ -948,218 +1045,306 @@
set i 0
set found_regexp 0
set curchar [string index $data $i]
- while {$curchar != "\$" && $curchar != "\[" &&
+ while {$curchar ne "\$" && $curchar ne "\[" &&
($curchar ne "\{" || !$found_regexp)} {
if {$curchar eq "\{"} {set found_regexp 1}
- if {[string match "-start" [string range $data $i [expr {$i+5}]]]} {
+ if {[string range $data $i $i+5] eq "-start"} {
incr i [length_exp [string range $data $i end]] ;# -start
incr i [length_exp [string range $data $i end]] ;# spaces
incr i [length_exp [string range $data $i end]] ;# expression - it could be a var
}
incr i [length_exp [string range $data $i end]]
set curchar [string index $data $i]
}
- return [expr {$i -1}]
+ return [expr {$i - 1}]
}
- array set HTML {
- comment {}
- /comment {}
- procs {}
- /procs {}
- str {}
- /str {}
- var {}
- /var {}
- object {}
- /object {}
+ ad_proc -private search_on_webindex {-page -host -root -proc} {
+ Search for a matching link in the page and return the absolute link if found
+ } {
+ set url ""
+ if { [regexp "\"'\]+)\[\"'\]\[^>\]*>$proc" $page match relative_url] } {
+ if {[string match "/*" $relative_url]} {
+ set url $host$relative_url
+ } else {
+ set url $root$relative_url
+ }
+ }
+ return $url
}
- # Keywords will be colored as other procs, but not hyperlinked
- # to api-doc pages. Perhaps we should hyperlink them to the TCL man pages?
- # else and elseif are be treated as special cases later
+ ad_proc -private pretty_token {kind token} {
+ Encode the specified token in HTML
+ } {
+ return "$token"
+ }
- set KEYWORDS [concat \
- {if while foreach for switch default} \
- {after break continue return error catch} \
- {upvar uplevel eval exec source variable namespace package load} \
- {set unset trace append global vwait split join} \
- {concat list lappend lset lindex linsert llength lrange lreplace lsearch lsort} \
- {info incr expr regexp regsub binary} \
- {string array open close read cd pwd glob seek pid} \
- {file fblocked fcopy fconfigure fileevent filename flush eof} \
- {clock encoding proc rename subst update} \
- {gets puts socket tell format scan} \
- ]
+ ad_proc -public tclcode_to_html {{-scope ""} {-proc_namespace ""} script} {
- if {[info command ::xotcl::api] ne ""} {
- set XOTCL_KEYWORDS [list self my next]
- # only command names are highlighted, otherwise we could add xotcl method
- # names by [lsort -unique [concat [list self my next] ..
- # [::xotcl::Object info methods] [::xotcl::Class info methods] ]]
- } else {
- set XOTCL_KEYWORDS {}
- }
+ Given a script, this proc formats it as HTML, including highlighting syntax in
+ various colors and creating hyperlinks to other proc definitions.
+ The inspiration for this proc was the tcl2html script created by Jeff Hobbs.
- # Returns a list of the commands from all namespaces.
- proc list_all_procs {{parentns ::}} {
- set result [info commands ${parentns}::*]
- foreach ns [namespace children $parentns] {
- set result [concat $result [list_all_procs $ns]]
- }
- return $result
- }
- set COMMANDS [list_all_procs]
+ @param script script to be formated in HTML
- set data [string map [list & "&" < "<" > ">"] \n$script]
+ } {
- set in_comment 0
- set in_quotes 0
- set proc_ok 1
- set l [string length $data]
- for {set i 0} {$i < $l} {incr i} {
- set char [string index $data $i]
- switch -- $char {
+ set script [string trimright $script]
+ template::head::add_style -style $::apidoc::style
- "\\" {
- append html [string range $data $i [incr i]]
- # This might have been a backslash added to escape &, <, or >.
- if {[regexp {^(amp;|lt;|gt;)} [string range $data $i end] match esc]} {
- append html $esc
- incr i [string length $esc]
- }
- }
+ # Keywords will be colored as other procs, but not hyperlinked
+ # to api-doc pages. Perhaps we should hyperlink them to the Tcl man pages?
+ # else and elseif are be treated as special cases later
- "\$" {
- if {$in_comment || ([string index $data [expr {$i + 1}]] == " ")} {
- append html "\$"
- } else {
- set varl [length_var [string range $data $i end]]
- append html "$HTML(var)[string range $data $i [expr {$i + $varl}]]$HTML(/var)"
- incr i $varl
- }
+ if {[info commands ::xotcl::api] ne ""} {
+ set XOTCL_KEYWORDS [list self my next]
+ # Only command names are highlighted, otherwise we could add XOTcl method
+ # names by [lsort -unique [concat [list self my next] ..
+ # [::xotcl::Object info methods] [::xotcl::Class info methods] ]]
+ } else {
+ set XOTCL_KEYWORDS {}
}
- "\"" {
- if {$in_comment} {
- append html "\""
- } elseif {$in_quotes} {
- append html \"$HTML(/str)
- set in_quotes 0
- } else {
- append html $HTML(str)\"
- set in_quotes 1
- set proc_ok 0
- }
- }
+ set data [string map [list & "&" < "<" > ">"] \n$script]
- "\#" {
- set prevchar [string index $data [expr {$i-1}]]
- if {$proc_ok && !$in_comment && [regexp {[\s;]} $prevchar]} {
- set in_comment 1
- set proc_ok 0
- append html $HTML(comment)
- }
- append html "#"
- }
+ set in_comment 0
+ set in_quotes 0
+ set proc_ok 1
+ set l [string length $data]
+ for {set i 0} {$i < $l} {incr i} {
+ set char [string index $data $i]
+ switch -- $char {
- "\n" {
- set proc_ok 1
- if {$in_quotes} {
- set proc_ok 0
- }
- if {$in_comment} {
- append html $HTML(/comment)
- }
- append html "\n"
- set in_comment 0
- }
+ "\\" {
+ append html [string range $data $i [incr i]]
+ # This might have been a backslash added to escape &, <, or >.
+ if {[regexp {^(amp;|lt;|gt;)} [string range $data $i end] match esc]} {
+ append html $esc
+ incr i [string length $esc]
+ }
+ }
- "\{" -
- ";" {
- if {!$in_quotes} {
- set proc_ok 1
- }
- append html $char
- }
+ "\$" {
+ if {$in_comment || [string index $data $i+1] eq " "} {
+ append html "\$"
+ } else {
+ set varl [length_var [string range $data $i end]]
+ append html [pretty_token var [string range $data $i $i+$varl]]
+ incr i $varl
+ }
+ }
- "\}" {
- append html "\}"
- # Special case else and elseif
- if {[regexp {^\}(\s*)(else|elseif)(\s*\{)} [string range $data $i end] match pre els post]} {
- append html "${pre}$HTML(procs)${els}$HTML(/procs)${post}"
- set proc_ok 1
- incr i [expr [string length $pre] + \
- [string length $els] + \
- [string length $post]]
- }
- }
+ "\"" {
+ if {$in_comment} {
+ append html \"
+ } elseif {$in_quotes} {
+ append html \"
+ set in_quotes 0
+ } else {
+ append html "" \"
+ set in_quotes 1
+ set proc_ok 0
+ }
+ }
- "\[" {
- if {!$in_comment} {
- set proc_ok 1
- }
- append html "\["
- }
+ "\#" {
+ set prevchar [string index $data $i-1]
+ if {$proc_ok && !$in_comment && [regexp {[\s;]} $prevchar]} {
+ set in_comment 1
+ set proc_ok 0
+ append html "
+ }
+ append html "\n"
+ set in_comment 0
+ }
- if {[lsearch -exact $KEYWORDS $proc_name] != -1 ||
- ([regexp {^::(.*)} $proc_name match had_colons] &&
- [lsearch -exact $KEYWORDS $had_colons] != -1)} {
- append html "$HTML(procs)${proc_name}$HTML(/procs)"
- } elseif {[lsearch -exact $XOTCL_KEYWORDS $proc_name] != -1 } {
- append html "$HTML(procs)${proc_name}$HTML(/procs)"
- } elseif {[api_is_xotcl_object $scope $proc_name]} {
- set url [::xotcl::api object_url \
- -show_source 1 -show_methods 2 \
- $scope $proc_name]
- append html "$HTML(object)${proc_name}$HTML(/object)"
- } elseif {[string match "ns*" $proc_name]} {
- set url "/api-doc/tcl-proc-view?tcl_proc=$proc_name"
- append html "$HTML(procs)${proc_name}$HTML(/procs)"
- } elseif {[string match "*__arg_parser" $proc_name]} {
- append html "$HTML(procs)${proc_name}$HTML(/procs)"
- } elseif {[lsearch -exact $COMMANDS ::${proc_namespace}::${proc_name}] != -1} {
- set url [api_proc_url ${proc_namespace}::${proc_name}]
- append html "$HTML(procs)${proc_name}$HTML(/procs)"
- } elseif {[lsearch -exact $COMMANDS ::$proc_name] != -1} {
- set url [api_proc_url $proc_name]
- append html "$HTML(procs)${proc_name}$HTML(/procs)"
- } else {
- append html ${proc_name}
- set proc_ok 1
+ "\{" -
+ ";" {
+ if {!$in_quotes} {
+ set proc_ok 1
+ }
+ append html $char
}
- incr i $procl
- # Hack for nasty regexp stuff
- if {"regexp" eq $proc_name || "regsub" eq $proc_name} {
- set regexpl [length_regexp [string range $data $i end]]
- append html [string range $data [expr {$i+1}] [expr {$i + $regexpl}]]
- incr i $regexpl
+ "\}" {
+ append html "\}"
+ # Special case else and elseif
+ if {[regexp {^\}(\s*)(else|elseif)(\s*\{)} [string range $data $i end] match pre els post]} {
+
+ append html $pre [pretty_token keyword $els] $post
+ set proc_ok 1
+ incr i [expr {[string length $pre] + [string length $els] + [string length $post]}]
+ }
}
- } else {
- append html $char
- set proc_ok 0
+
+ "\[" {
+ if {!$in_comment} {
+ set proc_ok 1
+ }
+ append html "\["
+ }
+
+ " " {
+ append html " "
+ }
+
+ default {
+ if {$proc_ok} {
+ set proc_ok 0
+ set procl [length_proc [string range $data $i end]]
+ set proc_name [string range $data $i $i+$procl]
+
+ if {$proc_name eq "*" || $proc_name eq "@"} {
+ append html $proc_name
+ } elseif {$proc_name in $::apidoc::KEYWORDS ||
+ ([regexp {^::(.*)} $proc_name match had_colons]
+ && $had_colons in $::apidoc::KEYWORDS)} {
+
+ set url "/api-doc/proc-view?proc=$proc_name"
+ append html "" \
+ [pretty_token keyword $proc_name]
+
+ #append html [pretty_token keyword $proc_name]
+
+ } elseif {$proc_name in $XOTCL_KEYWORDS} {
+ append html [pretty_token keyword $proc_name]
+
+ } elseif {[is_xotcl_object $scope $proc_name]} {
+ set url [::xotcl::api object_url \
+ -show_source 1 -show_methods 2 \
+ $scope $proc_name]
+ append html "" \
+ [pretty_token object $proc_name]
+
+ } elseif {[string match "ns*" $proc_name]} {
+ set url "/api-doc/tcl-proc-view?tcl_proc=$proc_name"
+ append html "" \
+ [pretty_token proc $proc_name]
+
+ } elseif {[string match "*__arg_parser" $proc_name]} {
+ append html [pretty_token helper $proc_name]
+
+ } elseif {$proc_namespace ne ""
+ && [info commands ::${proc_namespace}::${proc_name}] ne ""} {
+ set url [api_proc_url ${proc_namespace}::${proc_name}]
+ append html "" \
+ [pretty_token proc $proc_name]
+
+ } elseif {[info commands ::$proc_name] ne ""} {
+ set url [api_proc_url $proc_name]
+ append html "" \
+ [pretty_token proc $proc_name]
+
+ } else {
+ append html ${proc_name}
+ set proc_ok 1
+ }
+ incr i $procl
+
+ if {$proc_name eq "regexp" || $proc_name eq "regsub"} {
+ #
+ # Hack for nasty regexp stuff
+ #
+ set regexpl [length_regexp [string range $data $i end]]
+ append html [string range $data $i+1 $i+$regexpl]
+ incr i $regexpl
+ } elseif {$proc_name in {util_memoize util_memoize_seed}} {
+ #
+ # special cases for util_memoize
+ #
+ set reminder [string range $data $i+1 end]
+
+ if {[regexp {^(\s*\[\s*list)} $reminder _ list]} {
+ # util_memoize + list
+ append html " \[" [pretty_token keyword list]
+ incr i [string length $list]
+ set proc_ok 1
+ } else {
+ # util_memoize without list
+ set proc_ok 1
+ }
+ }
+ } else {
+ append html $char
+ set proc_ok 0
+ }
+ }
}
}
+
+ # We added a linefeed at the beginning to simplify processing
+ return [string range $html 1 end]
+ }
+
+ ad_proc -private xql_links_list { path } {
+
+ Returns list of xql files related to tcl script file
+ @param path path and filename from $::acs::rootdir
+
+ } {
+
+ set linkList [list]
+ set filename "$::acs::rootdir/$path"
+ set path_dirname [file dirname $path]
+ set file_dirname [file dirname $filename]
+ set file_rootname [file rootname [file tail $filename]]
+ regsub {(-oracle|-postgresql)$} $file_rootname {} file_rootname
+ set files \
+ [lsort -decreasing \
+ [glob -nocomplain \
+ -directory $file_dirname \
+ "${file_rootname}{,-}{,oracle,postgresql}.{adp,tcl,xql}" ]]
+
+ foreach file $files {
+ lappend linkList [list \
+ filename $file \
+ link "content-page-view?source_p=1&path=[ns_urlencode "$path_dirname/[file tail $file]"]" \
+ ]
+
}
+
+ return $linkList
}
- # We added a linefeed at the beginning to simplify processing
- return [string range $html 1 end]
+ ad_proc -private sanitize_path { {-prefix packages} path } {
+
+ Return a sanitized path. Cleans path from directory traversal
+ attacks and checks, if someone tries to access content outside
+ of the specified prefix.
+
+ @return sanitized path
+ } {
+
+ if {[regsub -all {[.][.]/} $path "" shortened_path]} {
+ set filename "$::acs::rootdir/$path"
+ ns_log notice [subst {INTRUDER ALERT:\n\nsomesone tried to snarf '$filename'!
+ file exists: [file exists $filename] user_id: [ad_conn user_id] peer: [ad_conn peeraddr]
+ }]
+ set path $shortened_path
+ }
+
+ if {![string match "$prefix/*" $path]} {
+ set filename "$::acs::rootdir/$path"
+ ns_log notice [subst {INTRUDER ALERT:\n\nsomesone tried to snarf '$filename'!
+ file exists: [file exists $filename] user_id: [ad_conn user_id] peer: [ad_conn peeraddr]
+ }]
+
+ set path $prefix/$path
+ }
+
+ return $path
+ }
}
@@ -1180,7 +1365,7 @@
@author Lars Pind (lars@pinds.com)
@creation-date 14 July 2000
} {
- return "/api-doc/proc-view?proc=[ns_urlencode $proc]"
+ return "/api-doc/proc-view?proc=[ns_urlencode $proc]&source_p=1"
}
ad_proc api_proc_link { proc } {
@@ -1192,34 +1377,10 @@
return "$proc"
}
-ad_proc -private api_xql_links_list { path } {
-
- Returns list of xql files related to tcl script file
- @param path path and filename from [acs_root_dir]
-
-
-} {
-
- set linkList [list]
- set filename "[acs_root_dir]/$path"
- set path_dirname [file dirname $path]
- set file_dirname [file dirname $filename]
- set file_rootname [file rootname [file tail $filename]]
- regsub {(-oracle|-postgresql)$} $file_rootname {} file_rootname
- set files \
- [lsort -decreasing \
- [glob -nocomplain \
- -directory $file_dirname \
- "${file_rootname}{,-}{,oracle,postgresql}.{adp,tcl,xql}" ]]
-
- foreach file $files {
- lappend linkList [list \
- filename $file \
- link "content-page-view?source_p=1&path=[ns_urlencode "$path_dirname/[file tail $file]"]" \
- ]
-
- }
- return $linkList
-
-}
+#
+# Local variables:
+# mode: tcl
+# tcl-indent-level: 4
+# indent-tabs-mode: nil
+# End: