# # 2014 August 24 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #-------------------------------------------------------------------------- # # This script extracts the documentation for the API used by fts5 auxiliary # functions from header file fts5.h. It outputs html text on stdout that # is included in the documentation on the web. # set ::fts5_docs_output "" if {[info commands hd_putsnl]==""} { if {[llength $argv]>0} { set ::extract_api_docs_mode [lindex $argv 0] } proc output {text} { puts $text } } else { proc output {text} { append ::fts5_docs_output "$text\n" } } if {[info exists ::extract_api_docs_mode]==0} {set ::extract_api_docs_mode api} set input_file [file join [file dir [info script]] fts5.h] set fd [open $input_file] set data [read $fd] close $fd # Argument $data is the entire text of the fts5.h file. This function # extracts the definition of the Fts5ExtensionApi structure from it and # returns a key/value list of structure member names and definitions. i.e. # # iVersion {int iVersion} xUserData {void *(*xUserData)(Fts5Context*)} ... # proc get_struct_members {data} { # Extract the structure definition from the fts5.h file. regexp "struct Fts5ExtensionApi {(.*?)};" $data -> defn # Remove all comments from the structure definition regsub -all {/[*].*?[*]/} $defn {} defn2 set res [list] foreach member [split $defn2 {;}] { set member [string trim $member] if {$member!=""} { catch { set name [lindex $member end] } regexp {.*?[(][*]([^)]*)[)]} $member -> name lappend res $name $member } } set res } proc get_struct_docs {data names} { # Extract the structure definition from the fts5.h file. regexp {EXTENSION API FUNCTIONS(.*?)[*]/} $data -> docs set current_doc "" set current_header "" foreach line [split $docs "\n"] { regsub {[*]*} $line {} line if {[regexp {^ } $line]} { append current_doc "$line\n" } elseif {[string trim $line]==""} { if {$current_header!=""} { append current_doc "\n" } } else { if {$current_doc != ""} { lappend res $current_header $current_doc set current_doc "" } set subject n/a regexp {^ *([[:alpha:]]*)} $line -> subject if {[lsearch $names $subject]>=0} { set current_header $subject } else { set current_header [string trim $line] } } } if {$current_doc != ""} { lappend res $current_header $current_doc } set res } proc get_tokenizer_docs {data} { regexp {(xCreate:.*?)[*]/} $data -> docs set res "
\n" foreach line [split [string trim $docs] "\n"] { regexp {[*][*](.*)} $line -> line if {[regexp {^ ?x.*:} $line]} { append res "
$line

\n" continue } if {[regexp {SYNONYM SUPPORT} $line]} { set line "

Synonym Support

" } if {[string trim $line] == ""} { append res "

\n" } else { append res "$line\n" } } set res } proc get_api_docs {data} { # Initialize global array M as a map from Fts5StructureApi member name # to member definition. i.e. # # iVersion -> {int iVersion} # xUserData -> {void *(*xUserData)(Fts5Context*)} # ... # array set M [get_struct_members $data] # Initialize global list D as a map from section name to documentation # text. Most (all?) section names are structure member names. # set D [get_struct_docs $data [array names M]] output "

" foreach {sub docs} $D { if {[info exists M($sub)]} { set hdr $M($sub) set link " id=$sub" } else { set link "" } #output "
" #set style "padding-left:6ex;font-size:1.4em;display:block" #output "
$hdr
" regsub -line {^ *[)]} $hdr ")" hdr output "
" output "$hdr
" set mode "" set margin " style=margin-top:0.1em" foreach line [split [string trim $docs] "\n"] { if {[string trim $line]==""} { if {$mode != ""} {output ""} set mode "" } elseif {$mode == ""} { if {[regexp {^ } $line]} { set mode codeblock } else { set mode p } output "<$mode$margin>" set margin "" } output $line } if {$mode != ""} {output ""} output "
" } output "
" } proc get_fts5_struct {data start end} { set res "" set bOut 0 foreach line [split $data "\n"] { if {$bOut==0} { if {[regexp $start $line]} { set bOut 1 } } if {$bOut} { append res "$line\n" } if {$bOut} { if {[regexp $end $line]} { set bOut 0 } } } set map [list /* /* */ */] string map $map $res } proc main {data} { switch $::extract_api_docs_mode { fts5_api { output [get_fts5_struct $data "typedef struct fts5_api" "^\};"] } fts5_tokenizer { output [get_fts5_struct $data "typedef struct Fts5Tokenizer" "^\};"] output [get_fts5_struct $data \ "Flags that may be passed as the third argument to xTokenize()" \ "#define FTS5_TOKEN_COLOCATED" ] } fts5_extension { output [get_fts5_struct $data "typedef.*Fts5ExtensionApi" "^.;"] } Fts5ExtensionApi { set struct [get_fts5_struct $data "^struct Fts5ExtensionApi" "^.;"] set map [list] foreach {k v} [get_struct_members $data] { if {[string match x* $k]==0} continue lappend map $k "$k" } output [string map $map $struct] } api { get_api_docs $data } tokenizer_api { output [get_tokenizer_docs $data] } default { } } } main $data set ::fts5_docs_output