extract_api_docs.tcl 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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. set ::fts5_docs_output ""
  18. if {[info commands hd_putsnl]==""} {
  19. if {[llength $argv]>0} { set ::extract_api_docs_mode [lindex $argv 0] }
  20. proc output {text} {
  21. puts $text
  22. }
  23. } else {
  24. proc output {text} {
  25. append ::fts5_docs_output "$text\n"
  26. }
  27. }
  28. if {[info exists ::extract_api_docs_mode]==0} {set ::extract_api_docs_mode api}
  29. set input_file [file join [file dir [info script]] fts5.h]
  30. set fd [open $input_file]
  31. set data [read $fd]
  32. close $fd
  33. # Argument $data is the entire text of the fts5.h file. This function
  34. # extracts the definition of the Fts5ExtensionApi structure from it and
  35. # returns a key/value list of structure member names and definitions. i.e.
  36. #
  37. # iVersion {int iVersion} xUserData {void *(*xUserData)(Fts5Context*)} ...
  38. #
  39. proc get_struct_members {data} {
  40. # Extract the structure definition from the fts5.h file.
  41. regexp "struct Fts5ExtensionApi {(.*?)};" $data -> defn
  42. # Remove all comments from the structure definition
  43. regsub -all {/[*].*?[*]/} $defn {} defn2
  44. set res [list]
  45. foreach member [split $defn2 {;}] {
  46. set member [string trim $member]
  47. if {$member!=""} {
  48. catch { set name [lindex $member end] }
  49. regexp {.*?[(][*]([^)]*)[)]} $member -> name
  50. lappend res $name $member
  51. }
  52. }
  53. set res
  54. }
  55. proc get_struct_docs {data names} {
  56. # Extract the structure definition from the fts5.h file.
  57. regexp {EXTENSION API FUNCTIONS(.*?)[*]/} $data -> docs
  58. set current_doc ""
  59. set current_header ""
  60. foreach line [split $docs "\n"] {
  61. regsub {[*]*} $line {} line
  62. if {[regexp {^ } $line]} {
  63. append current_doc "$line\n"
  64. } elseif {[string trim $line]==""} {
  65. if {$current_header!=""} { append current_doc "\n" }
  66. } else {
  67. if {$current_doc != ""} {
  68. lappend res $current_header $current_doc
  69. set current_doc ""
  70. }
  71. set subject n/a
  72. regexp {^ *([[:alnum:]_]*)} $line -> subject
  73. if {[lsearch $names $subject]>=0} {
  74. set current_header $subject
  75. } else {
  76. set current_header [string trim $line]
  77. }
  78. }
  79. }
  80. if {$current_doc != ""} {
  81. lappend res $current_header $current_doc
  82. }
  83. set res
  84. }
  85. proc get_tokenizer_docs {data} {
  86. regexp {(xCreate:.*?)[*]/} $data -> docs
  87. set res "<dl>\n"
  88. foreach line [split [string trim $docs] "\n"] {
  89. regexp {[*][*](.*)} $line -> line
  90. if {[regexp {^ ?x.*:} $line]} {
  91. append res "<dt><b>$line</b></dt><dd><p style=margin-top:0>\n"
  92. continue
  93. }
  94. if {[regexp {FTS5_TOKENIZER} $line]} {
  95. set line </dl><p>
  96. }
  97. if {[regexp {SYNONYM SUPPORT} $line]} {
  98. set line "<h3>Synonym Support</h3>"
  99. }
  100. if {[string trim $line] == ""} {
  101. append res "<p>\n"
  102. } else {
  103. append res "$line\n"
  104. }
  105. }
  106. set res
  107. }
  108. proc get_api_docs {data} {
  109. # Initialize global array M as a map from Fts5StructureApi member name
  110. # to member definition. i.e.
  111. #
  112. # iVersion -> {int iVersion}
  113. # xUserData -> {void *(*xUserData)(Fts5Context*)}
  114. # ...
  115. #
  116. array set M [get_struct_members $data]
  117. # Initialize global list D as a map from section name to documentation
  118. # text. Most (all?) section names are structure member names.
  119. #
  120. set D [get_struct_docs $data [array names M]]
  121. output "<dl>"
  122. foreach {sub docs} $D {
  123. if {[info exists M($sub)]} {
  124. set hdr $M($sub)
  125. set link " id=$sub"
  126. } else {
  127. set link ""
  128. }
  129. #output "<hr color=#eeeee style=\"margin:1em 8.4ex 0 8.4ex;\"$link>"
  130. #set style "padding-left:6ex;font-size:1.4em;display:block"
  131. #output "<h style=\"$style\"><pre>$hdr</pre></h>"
  132. regsub -line {^ *[)]} $hdr ")" hdr
  133. output "<dt style=\"white-space:pre;font-family:monospace;font-size:120%\""
  134. output "$link>"
  135. output "<b>$hdr</b></dt><dd>"
  136. set mode ""
  137. set margin " style=margin-top:0.1em"
  138. foreach line [split [string trim $docs] "\n"] {
  139. if {[string trim $line]==""} {
  140. if {$mode != ""} {output "</$mode>"}
  141. set mode ""
  142. } elseif {$mode == ""} {
  143. if {[regexp {^ } $line]} {
  144. set mode codeblock
  145. } else {
  146. set mode p
  147. }
  148. output "<$mode$margin>"
  149. set margin ""
  150. }
  151. output $line
  152. }
  153. if {$mode != ""} {output "</$mode>"}
  154. output "</dd>"
  155. }
  156. output "</dl>"
  157. }
  158. proc get_fts5_struct {data start end} {
  159. set res ""
  160. set bOut 0
  161. foreach line [split $data "\n"] {
  162. if {$bOut==0} {
  163. if {[regexp $start $line]} {
  164. set bOut 1
  165. }
  166. }
  167. if {$bOut} {
  168. append res "$line\n"
  169. }
  170. if {$bOut} {
  171. if {[regexp $end $line]} {
  172. set bOut 0
  173. }
  174. }
  175. }
  176. set map [list /* <i>/* */ */</i>]
  177. string map $map $res
  178. }
  179. proc main {data} {
  180. switch $::extract_api_docs_mode {
  181. fts5_api {
  182. output [get_fts5_struct $data "typedef struct fts5_api" "^\};"]
  183. }
  184. fts5_tokenizer {
  185. output [get_fts5_struct $data "typedef struct Fts5Tokenizer" "^\};"]
  186. output [get_fts5_struct $data \
  187. "Flags that may be passed as the third argument to xTokenize()" \
  188. "#define FTS5_TOKEN_COLOCATED"
  189. ]
  190. }
  191. fts5_extension {
  192. output [get_fts5_struct $data "typedef.*Fts5ExtensionApi" "^.;"]
  193. }
  194. Fts5ExtensionApi {
  195. set struct [get_fts5_struct $data "^struct Fts5ExtensionApi" "^.;"]
  196. set map [list]
  197. set lKey [list]
  198. foreach {k v} [get_struct_members $data] {
  199. if {[string match x* $k]==0} continue
  200. lappend lKey $k
  201. }
  202. foreach k [lsort -decr $lKey] { lappend map $k "<a href=#$k>$k</a>" }
  203. output [string map $map $struct]
  204. }
  205. api {
  206. get_api_docs $data
  207. }
  208. tokenizer_api {
  209. output [get_tokenizer_docs $data]
  210. }
  211. default {
  212. }
  213. }
  214. }
  215. main $data
  216. set ::fts5_docs_output