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]==""} {
20*27277c4eSdan  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} {
26*27277c4eSdan    append ::fts5_docs_output "$text\n"
2748d70140Sdan  }
2848d70140Sdan}
29*27277c4eSdanif {[info exists ::extract_api_docs_mode]==0} {set ::extract_api_docs_mode api}
30*27277c4eSdan
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.
47*27277c4eSdan  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
101*27277c4eSdanproc get_tokenizer_docs {data} {
102*27277c4eSdan  regexp {(xCreate:.*?)[*]/} $data -> docs
103*27277c4eSdan
104*27277c4eSdan  set res "<dl>\n"
105*27277c4eSdan  foreach line [split [string trim $docs] "\n"] {
106*27277c4eSdan    regexp {[*][*](.*)} $line -> line
107*27277c4eSdan    if {[regexp {^ ?x.*:} $line]} {
108*27277c4eSdan      append res "<dt><b>$line</b></dt><dd><p style=margin-top:0>\n"
109*27277c4eSdan      continue
110*27277c4eSdan    }
111*27277c4eSdan    if {[string trim $line] == ""} {
112*27277c4eSdan      append res "<p>\n"
113*27277c4eSdan    } else {
114*27277c4eSdan      append res "$line\n"
115*27277c4eSdan    }
116*27277c4eSdan  }
117*27277c4eSdan  append res "</dl>\n"
118*27277c4eSdan
119*27277c4eSdan  set res
120*27277c4eSdan}
121*27277c4eSdan
122*27277c4eSdanproc get_api_docs {data} {
1234aee5dffSdan  # Initialize global array M as a map from Fts5StructureApi member name
1244aee5dffSdan  # to member definition. i.e.
1254aee5dffSdan  #
1264aee5dffSdan  #   iVersion  -> {int iVersion}
1274aee5dffSdan  #   xUserData -> {void *(*xUserData)(Fts5Context*)}
1284aee5dffSdan  #   ...
1294aee5dffSdan  #
1304aee5dffSdan  array set M [get_struct_members $data]
1314aee5dffSdan
1324aee5dffSdan  # Initialize global list D as a map from section name to documentation
1334aee5dffSdan  # text. Most (all?) section names are structure member names.
1344aee5dffSdan  #
1354aee5dffSdan  set D [get_struct_docs $data [array names M]]
1364aee5dffSdan
137*27277c4eSdan  foreach {sub docs} $D {
138*27277c4eSdan    if {[info exists M($sub)]} {
139*27277c4eSdan      set hdr $M($sub)
140*27277c4eSdan      set link " id=$sub"
141*27277c4eSdan    } else {
142*27277c4eSdan      set link ""
1434aee5dffSdan    }
144*27277c4eSdan
145*27277c4eSdan    output "<hr color=#eeeee style=\"margin:1em 8.4ex 0 8.4ex;\"$link>"
146*27277c4eSdan    set style "padding-left:6ex;font-size:1.4em;display:block"
147*27277c4eSdan    output "<h style=\"$style\"><pre>$hdr</pre></h>"
1484aee5dffSdan
1494aee5dffSdan    set mode ""
1504aee5dffSdan    set bEmpty 1
1514aee5dffSdan    foreach line [split [string trim $docs] "\n"] {
1524aee5dffSdan      if {[string trim $line]==""} {
15348d70140Sdan        if {$mode != ""} {output "</$mode>"}
1544aee5dffSdan        set mode ""
1554aee5dffSdan      } elseif {$mode == ""} {
1564aee5dffSdan        if {[regexp {^     } $line]} {
15748d70140Sdan          set mode codeblock
1584aee5dffSdan        } else {
1594aee5dffSdan          set mode p
1604aee5dffSdan        }
16148d70140Sdan        output "<$mode>"
1624aee5dffSdan      }
16348d70140Sdan      output $line
1644aee5dffSdan    }
16548d70140Sdan    if {$mode != ""} {output "</$mode>"}
1664aee5dffSdan  }
167*27277c4eSdan}
168*27277c4eSdan
169*27277c4eSdanproc get_fts5_struct {data start end} {
170*27277c4eSdan  set res ""
171*27277c4eSdan  set bOut 0
172*27277c4eSdan  foreach line [split $data "\n"] {
173*27277c4eSdan    if {$bOut==0} {
174*27277c4eSdan      if {[regexp $start $line]} {
175*27277c4eSdan        set bOut 1
176*27277c4eSdan      }
177*27277c4eSdan    }
178*27277c4eSdan
179*27277c4eSdan    if {$bOut} {
180*27277c4eSdan      append res "$line\n"
181*27277c4eSdan    }
182*27277c4eSdan
183*27277c4eSdan    if {$bOut} {
184*27277c4eSdan      if {[regexp $end $line]} {
185*27277c4eSdan        set bOut 0
186*27277c4eSdan      }
187*27277c4eSdan    }
188*27277c4eSdan  }
189*27277c4eSdan
190*27277c4eSdan  set map [list /* <i>/* */ */</i>]
191*27277c4eSdan  string map $map $res
192*27277c4eSdan}
193*27277c4eSdan
194*27277c4eSdanproc main {data} {
195*27277c4eSdan  switch $::extract_api_docs_mode {
196*27277c4eSdan    fts5_api {
197*27277c4eSdan      output [get_fts5_struct $data "typedef struct fts5_api" "^\};"]
198*27277c4eSdan    }
199*27277c4eSdan
200*27277c4eSdan    fts5_tokenizer {
201*27277c4eSdan      output [get_fts5_struct $data "typedef struct Fts5Tokenizer" "^\};"]
202*27277c4eSdan    }
203*27277c4eSdan
204*27277c4eSdan    fts5_extension {
205*27277c4eSdan      output [get_fts5_struct $data "typedef.*Fts5ExtensionApi" "^.;"]
206*27277c4eSdan    }
207*27277c4eSdan
208*27277c4eSdan    Fts5ExtensionApi {
209*27277c4eSdan      set struct [get_fts5_struct $data "^struct Fts5ExtensionApi" "^.;"]
210*27277c4eSdan      set map [list]
211*27277c4eSdan      foreach {k v} [get_struct_members $data] {
212*27277c4eSdan        if {[string match x* $k]==0} continue
213*27277c4eSdan        lappend map $k "<a href=#$k>$k</a>"
214*27277c4eSdan      }
215*27277c4eSdan      output [string map $map $struct]
216*27277c4eSdan    }
217*27277c4eSdan
218*27277c4eSdan    api {
219*27277c4eSdan      get_api_docs $data
220*27277c4eSdan    }
221*27277c4eSdan
222*27277c4eSdan    tokenizer_api {
223*27277c4eSdan      output [get_tokenizer_docs $data]
224*27277c4eSdan    }
225*27277c4eSdan
226*27277c4eSdan    default {
227*27277c4eSdan    }
228*27277c4eSdan  }
229*27277c4eSdan}
230*27277c4eSdanmain $data
2314aee5dffSdan
23248d70140Sdanset ::fts5_docs_output
2334aee5dffSdan
2344aee5dffSdan
2354aee5dffSdan
2364aee5dffSdan
2374aee5dffSdan
238