1#
2# 2014 August 24
3#
4# The author disclaims copyright to this source code.  In place of
5# a legal notice, here is a blessing:
6#
7#    May you do good and not evil.
8#    May you find forgiveness for yourself and forgive others.
9#    May you share freely, never taking more than you give.
10#
11#--------------------------------------------------------------------------
12#
13# This script extracts the documentation for the API used by fts5 auxiliary
14# functions from header file fts5.h. It outputs html text on stdout that
15# is included in the documentation on the web.
16#
17
18set ::fts5_docs_output ""
19if {[info commands hd_putsnl]==""} {
20  if {[llength $argv]>0} { set ::extract_api_docs_mode [lindex $argv 0] }
21  proc output {text} {
22    puts $text
23  }
24} else {
25  proc output {text} {
26    append ::fts5_docs_output "$text\n"
27  }
28}
29if {[info exists ::extract_api_docs_mode]==0} {set ::extract_api_docs_mode api}
30
31
32set input_file [file join [file dir [info script]] fts5.h]
33set fd [open $input_file]
34set data [read $fd]
35close $fd
36
37
38# Argument $data is the entire text of the fts5.h file. This function
39# extracts the definition of the Fts5ExtensionApi structure from it and
40# returns a key/value list of structure member names and definitions. i.e.
41#
42#   iVersion {int iVersion} xUserData {void *(*xUserData)(Fts5Context*)} ...
43#
44proc get_struct_members {data} {
45
46  # Extract the structure definition from the fts5.h file.
47  regexp "struct Fts5ExtensionApi {(.*?)};" $data -> defn
48
49  # Remove all comments from the structure definition
50  regsub -all {/[*].*?[*]/} $defn {} defn2
51
52  set res [list]
53  foreach member [split $defn2 {;}] {
54
55    set member [string trim $member]
56    if {$member!=""} {
57      catch { set name [lindex $member end] }
58      regexp {.*?[(][*]([^)]*)[)]} $member -> name
59      lappend res $name $member
60    }
61  }
62
63  set res
64}
65
66proc get_struct_docs {data names} {
67  # Extract the structure definition from the fts5.h file.
68  regexp {EXTENSION API FUNCTIONS(.*?)[*]/} $data -> docs
69
70  set current_doc    ""
71  set current_header ""
72
73  foreach line [split $docs "\n"] {
74    regsub {[*]*} $line {} line
75    if {[regexp {^  } $line]} {
76      append current_doc "$line\n"
77    } elseif {[string trim $line]==""} {
78      if {$current_header!=""} { append current_doc "\n" }
79    } else {
80      if {$current_doc != ""} {
81        lappend res $current_header $current_doc
82        set current_doc ""
83      }
84      set subject n/a
85      regexp {^ *([[:alpha:]]*)} $line -> subject
86      if {[lsearch $names $subject]>=0} {
87        set current_header $subject
88      } else {
89        set current_header [string trim $line]
90      }
91    }
92  }
93
94  if {$current_doc != ""} {
95    lappend res $current_header $current_doc
96  }
97
98  set res
99}
100
101proc get_tokenizer_docs {data} {
102  regexp {(xCreate:.*?)[*]/} $data -> docs
103
104  set res "<dl>\n"
105  foreach line [split [string trim $docs] "\n"] {
106    regexp {[*][*](.*)} $line -> line
107    if {[regexp {^ ?x.*:} $line]} {
108      append res "<dt><b>$line</b></dt><dd><p style=margin-top:0>\n"
109      continue
110    }
111    if {[regexp {SYNONYM SUPPORT} $line]} {
112      set line "</dl><h3>Synonym Support</h3>"
113    }
114    if {[string trim $line] == ""} {
115      append res "<p>\n"
116    } else {
117      append res "$line\n"
118    }
119  }
120
121  set res
122}
123
124proc get_api_docs {data} {
125  # Initialize global array M as a map from Fts5StructureApi member name
126  # to member definition. i.e.
127  #
128  #   iVersion  -> {int iVersion}
129  #   xUserData -> {void *(*xUserData)(Fts5Context*)}
130  #   ...
131  #
132  array set M [get_struct_members $data]
133
134  # Initialize global list D as a map from section name to documentation
135  # text. Most (all?) section names are structure member names.
136  #
137  set D [get_struct_docs $data [array names M]]
138
139  output "<dl>"
140  foreach {sub docs} $D {
141    if {[info exists M($sub)]} {
142      set hdr $M($sub)
143      set link " id=$sub"
144    } else {
145      set link ""
146    }
147
148    #output "<hr color=#eeeee style=\"margin:1em 8.4ex 0 8.4ex;\"$link>"
149    #set style "padding-left:6ex;font-size:1.4em;display:block"
150    #output "<h style=\"$style\"><pre>$hdr</pre></h>"
151
152    regsub -line {^  *[)]} $hdr ")" hdr
153    output "<dt style=\"white-space:pre;font-family:monospace;font-size:120%\""
154    output "$link>"
155    output "<b>$hdr</b></dt><dd>"
156
157    set mode ""
158    set margin " style=margin-top:0.1em"
159    foreach line [split [string trim $docs] "\n"] {
160      if {[string trim $line]==""} {
161        if {$mode != ""} {output "</$mode>"}
162        set mode ""
163      } elseif {$mode == ""} {
164        if {[regexp {^     } $line]} {
165          set mode codeblock
166        } else {
167          set mode p
168        }
169        output "<$mode$margin>"
170        set margin ""
171      }
172      output $line
173    }
174    if {$mode != ""} {output "</$mode>"}
175    output "</dd>"
176  }
177  output "</dl>"
178}
179
180proc get_fts5_struct {data start end} {
181  set res ""
182  set bOut 0
183  foreach line [split $data "\n"] {
184    if {$bOut==0} {
185      if {[regexp $start $line]} {
186        set bOut 1
187      }
188    }
189
190    if {$bOut} {
191      append res "$line\n"
192    }
193
194    if {$bOut} {
195      if {[regexp $end $line]} {
196        set bOut 0
197      }
198    }
199  }
200
201  set map [list /* <i>/* */ */</i>]
202  string map $map $res
203}
204
205proc main {data} {
206  switch $::extract_api_docs_mode {
207    fts5_api {
208      output [get_fts5_struct $data "typedef struct fts5_api" "^\};"]
209    }
210
211    fts5_tokenizer {
212      output [get_fts5_struct $data "typedef struct Fts5Tokenizer" "^\};"]
213      output [get_fts5_struct $data \
214        "Flags that may be passed as the third argument to xTokenize()" \
215        "#define FTS5_TOKEN_COLOCATED"
216      ]
217    }
218
219    fts5_extension {
220      output [get_fts5_struct $data "typedef.*Fts5ExtensionApi" "^.;"]
221    }
222
223    Fts5ExtensionApi {
224      set struct [get_fts5_struct $data "^struct Fts5ExtensionApi" "^.;"]
225      set map [list]
226      foreach {k v} [get_struct_members $data] {
227        if {[string match x* $k]==0} continue
228        lappend map $k "<a href=#$k>$k</a>"
229      }
230      output [string map $map $struct]
231    }
232
233    api {
234      get_api_docs $data
235    }
236
237    tokenizer_api {
238      output [get_tokenizer_docs $data]
239    }
240
241    default {
242    }
243  }
244}
245main $data
246
247set ::fts5_docs_output
248
249
250
251
252
253