14aee5dffSdan#
24aee5dffSdan# 2014 August 24
34aee5dffSdan#
44aee5dffSdan# The author disclaims copyright to this source code.  In place of
54aee5dffSdan# a legal notice, here is a blessing:
64aee5dffSdan#
74aee5dffSdan#    May you do good and not evil.
84aee5dffSdan#    May you find forgiveness for yourself and forgive others.
94aee5dffSdan#    May you share freely, never taking more than you give.
104aee5dffSdan#
114aee5dffSdan#--------------------------------------------------------------------------
124aee5dffSdan#
134aee5dffSdan# This script extracts the documentation for the API used by fts5 auxiliary
144aee5dffSdan# functions from header file fts5.h. It outputs html text on stdout that
154aee5dffSdan# is included in the documentation on the web.
164aee5dffSdan#
174aee5dffSdan
1848d70140Sdanset ::fts5_docs_output ""
1948d70140Sdanif {[info commands hd_putsnl]==""} {
2027277c4eSdan  if {[llength $argv]>0} { set ::extract_api_docs_mode [lindex $argv 0] }
2148d70140Sdan  proc output {text} {
2248d70140Sdan    puts $text
2348d70140Sdan  }
2448d70140Sdan} else {
2548d70140Sdan  proc output {text} {
2627277c4eSdan    append ::fts5_docs_output "$text\n"
2748d70140Sdan  }
2848d70140Sdan}
2927277c4eSdanif {[info exists ::extract_api_docs_mode]==0} {set ::extract_api_docs_mode api}
3027277c4eSdan
3148d70140Sdan
324aee5dffSdanset input_file [file join [file dir [info script]] fts5.h]
334aee5dffSdanset fd [open $input_file]
344aee5dffSdanset data [read $fd]
354aee5dffSdanclose $fd
364aee5dffSdan
374aee5dffSdan
384aee5dffSdan# Argument $data is the entire text of the fts5.h file. This function
394aee5dffSdan# extracts the definition of the Fts5ExtensionApi structure from it and
404aee5dffSdan# returns a key/value list of structure member names and definitions. i.e.
414aee5dffSdan#
424aee5dffSdan#   iVersion {int iVersion} xUserData {void *(*xUserData)(Fts5Context*)} ...
434aee5dffSdan#
444aee5dffSdanproc get_struct_members {data} {
454aee5dffSdan
464aee5dffSdan  # Extract the structure definition from the fts5.h file.
4727277c4eSdan  regexp "struct Fts5ExtensionApi {(.*?)};" $data -> defn
484aee5dffSdan
494aee5dffSdan  # Remove all comments from the structure definition
504aee5dffSdan  regsub -all {/[*].*?[*]/} $defn {} defn2
514aee5dffSdan
524aee5dffSdan  set res [list]
534aee5dffSdan  foreach member [split $defn2 {;}] {
544aee5dffSdan
554aee5dffSdan    set member [string trim $member]
564aee5dffSdan    if {$member!=""} {
574aee5dffSdan      catch { set name [lindex $member end] }
584aee5dffSdan      regexp {.*?[(][*]([^)]*)[)]} $member -> name
594aee5dffSdan      lappend res $name $member
604aee5dffSdan    }
614aee5dffSdan  }
624aee5dffSdan
634aee5dffSdan  set res
644aee5dffSdan}
654aee5dffSdan
664aee5dffSdanproc get_struct_docs {data names} {
674aee5dffSdan  # Extract the structure definition from the fts5.h file.
684aee5dffSdan  regexp {EXTENSION API FUNCTIONS(.*?)[*]/} $data -> docs
694aee5dffSdan
704aee5dffSdan  set current_doc    ""
714aee5dffSdan  set current_header ""
724aee5dffSdan
734aee5dffSdan  foreach line [split $docs "\n"] {
744aee5dffSdan    regsub {[*]*} $line {} line
754aee5dffSdan    if {[regexp {^  } $line]} {
764aee5dffSdan      append current_doc "$line\n"
774aee5dffSdan    } elseif {[string trim $line]==""} {
784aee5dffSdan      if {$current_header!=""} { append current_doc "\n" }
794aee5dffSdan    } else {
804aee5dffSdan      if {$current_doc != ""} {
814aee5dffSdan        lappend res $current_header $current_doc
824aee5dffSdan        set current_doc ""
834aee5dffSdan      }
844aee5dffSdan      set subject n/a
854aee5dffSdan      regexp {^ *([[:alpha:]]*)} $line -> subject
864aee5dffSdan      if {[lsearch $names $subject]>=0} {
874aee5dffSdan        set current_header $subject
884aee5dffSdan      } else {
894aee5dffSdan        set current_header [string trim $line]
904aee5dffSdan      }
914aee5dffSdan    }
924aee5dffSdan  }
934aee5dffSdan
944aee5dffSdan  if {$current_doc != ""} {
954aee5dffSdan    lappend res $current_header $current_doc
964aee5dffSdan  }
974aee5dffSdan
984aee5dffSdan  set res
994aee5dffSdan}
1004aee5dffSdan
10127277c4eSdanproc get_tokenizer_docs {data} {
10227277c4eSdan  regexp {(xCreate:.*?)[*]/} $data -> docs
10327277c4eSdan
10427277c4eSdan  set res "<dl>\n"
10527277c4eSdan  foreach line [split [string trim $docs] "\n"] {
10627277c4eSdan    regexp {[*][*](.*)} $line -> line
10727277c4eSdan    if {[regexp {^ ?x.*:} $line]} {
10827277c4eSdan      append res "<dt><b>$line</b></dt><dd><p style=margin-top:0>\n"
10927277c4eSdan      continue
11027277c4eSdan    }
111*ea8b93eeSdan    if {[regexp {SYNONYM SUPPORT} $line]} {
112*ea8b93eeSdan      set line "</dl><h3>Synonym Support</h3>"
113*ea8b93eeSdan    }
11427277c4eSdan    if {[string trim $line] == ""} {
11527277c4eSdan      append res "<p>\n"
11627277c4eSdan    } else {
11727277c4eSdan      append res "$line\n"
11827277c4eSdan    }
11927277c4eSdan  }
12027277c4eSdan
12127277c4eSdan  set res
12227277c4eSdan}
12327277c4eSdan
12427277c4eSdanproc get_api_docs {data} {
1254aee5dffSdan  # Initialize global array M as a map from Fts5StructureApi member name
1264aee5dffSdan  # to member definition. i.e.
1274aee5dffSdan  #
1284aee5dffSdan  #   iVersion  -> {int iVersion}
1294aee5dffSdan  #   xUserData -> {void *(*xUserData)(Fts5Context*)}
1304aee5dffSdan  #   ...
1314aee5dffSdan  #
1324aee5dffSdan  array set M [get_struct_members $data]
1334aee5dffSdan
1344aee5dffSdan  # Initialize global list D as a map from section name to documentation
1354aee5dffSdan  # text. Most (all?) section names are structure member names.
1364aee5dffSdan  #
1374aee5dffSdan  set D [get_struct_docs $data [array names M]]
1384aee5dffSdan
1393eb9024dSdan  output "<dl>"
14027277c4eSdan  foreach {sub docs} $D {
14127277c4eSdan    if {[info exists M($sub)]} {
14227277c4eSdan      set hdr $M($sub)
14327277c4eSdan      set link " id=$sub"
14427277c4eSdan    } else {
14527277c4eSdan      set link ""
1464aee5dffSdan    }
14727277c4eSdan
1483eb9024dSdan    #output "<hr color=#eeeee style=\"margin:1em 8.4ex 0 8.4ex;\"$link>"
1493eb9024dSdan    #set style "padding-left:6ex;font-size:1.4em;display:block"
1503eb9024dSdan    #output "<h style=\"$style\"><pre>$hdr</pre></h>"
1513eb9024dSdan
1523eb9024dSdan    regsub -line {^  *[)]} $hdr ")" hdr
1533eb9024dSdan    output "<dt style=\"white-space:pre;font-family:monospace;font-size:120%\""
1543eb9024dSdan    output "$link>"
1553eb9024dSdan    output "<b>$hdr</b></dt><dd>"
1564aee5dffSdan
1574aee5dffSdan    set mode ""
1583eb9024dSdan    set margin " style=margin-top:0.1em"
1594aee5dffSdan    foreach line [split [string trim $docs] "\n"] {
1604aee5dffSdan      if {[string trim $line]==""} {
16148d70140Sdan        if {$mode != ""} {output "</$mode>"}
1624aee5dffSdan        set mode ""
1634aee5dffSdan      } elseif {$mode == ""} {
1644aee5dffSdan        if {[regexp {^     } $line]} {
16548d70140Sdan          set mode codeblock
1664aee5dffSdan        } else {
1674aee5dffSdan          set mode p
1684aee5dffSdan        }
1693eb9024dSdan        output "<$mode$margin>"
1703eb9024dSdan        set margin ""
1714aee5dffSdan      }
17248d70140Sdan      output $line
1734aee5dffSdan    }
17448d70140Sdan    if {$mode != ""} {output "</$mode>"}
1753eb9024dSdan    output "</dd>"
1764aee5dffSdan  }
1773eb9024dSdan  output "</dl>"
17827277c4eSdan}
17927277c4eSdan
18027277c4eSdanproc get_fts5_struct {data start end} {
18127277c4eSdan  set res ""
18227277c4eSdan  set bOut 0
18327277c4eSdan  foreach line [split $data "\n"] {
18427277c4eSdan    if {$bOut==0} {
18527277c4eSdan      if {[regexp $start $line]} {
18627277c4eSdan        set bOut 1
18727277c4eSdan      }
18827277c4eSdan    }
18927277c4eSdan
19027277c4eSdan    if {$bOut} {
19127277c4eSdan      append res "$line\n"
19227277c4eSdan    }
19327277c4eSdan
19427277c4eSdan    if {$bOut} {
19527277c4eSdan      if {[regexp $end $line]} {
19627277c4eSdan        set bOut 0
19727277c4eSdan      }
19827277c4eSdan    }
19927277c4eSdan  }
20027277c4eSdan
20127277c4eSdan  set map [list /* <i>/* */ */</i>]
20227277c4eSdan  string map $map $res
20327277c4eSdan}
20427277c4eSdan
20527277c4eSdanproc main {data} {
20627277c4eSdan  switch $::extract_api_docs_mode {
20727277c4eSdan    fts5_api {
20827277c4eSdan      output [get_fts5_struct $data "typedef struct fts5_api" "^\};"]
20927277c4eSdan    }
21027277c4eSdan
21127277c4eSdan    fts5_tokenizer {
21227277c4eSdan      output [get_fts5_struct $data "typedef struct Fts5Tokenizer" "^\};"]
213*ea8b93eeSdan      output [get_fts5_struct $data \
214*ea8b93eeSdan        "Flags that may be passed as the third argument to xTokenize()" \
215*ea8b93eeSdan        "#define FTS5_TOKEN_COLOCATED"
216*ea8b93eeSdan      ]
21727277c4eSdan    }
21827277c4eSdan
21927277c4eSdan    fts5_extension {
22027277c4eSdan      output [get_fts5_struct $data "typedef.*Fts5ExtensionApi" "^.;"]
22127277c4eSdan    }
22227277c4eSdan
22327277c4eSdan    Fts5ExtensionApi {
22427277c4eSdan      set struct [get_fts5_struct $data "^struct Fts5ExtensionApi" "^.;"]
22527277c4eSdan      set map [list]
22627277c4eSdan      foreach {k v} [get_struct_members $data] {
22727277c4eSdan        if {[string match x* $k]==0} continue
22827277c4eSdan        lappend map $k "<a href=#$k>$k</a>"
22927277c4eSdan      }
23027277c4eSdan      output [string map $map $struct]
23127277c4eSdan    }
23227277c4eSdan
23327277c4eSdan    api {
23427277c4eSdan      get_api_docs $data
23527277c4eSdan    }
23627277c4eSdan
23727277c4eSdan    tokenizer_api {
23827277c4eSdan      output [get_tokenizer_docs $data]
23927277c4eSdan    }
24027277c4eSdan
24127277c4eSdan    default {
24227277c4eSdan    }
24327277c4eSdan  }
24427277c4eSdan}
24527277c4eSdanmain $data
2464aee5dffSdan
24748d70140Sdanset ::fts5_docs_output
2484aee5dffSdan
2494aee5dffSdan
2504aee5dffSdan
2514aee5dffSdan
2524aee5dffSdan
253