c18513879185761ce2bb51ab31ad7d274ad16a16
[platform/upstream/doxygen.git] / addon / doxypysql / search.py
1 #!/usr/bin/python
2
3 # python script to search through doxygen_sqlite3.db
4 #
5 # Permission to use, copy, modify, and distribute this software and its
6 # documentation under the terms of the GNU General Public License is hereby
7 # granted. No representations are made about the suitability of this software
8 # for any purpose. It is provided "as is" without express or implied warranty.
9 # See the GNU General Public License for more details.
10 #
11
12 import sqlite3
13 import sys
14 import os
15 import getopt
16 import json
17 import re
18
19 class MemberType:
20   Define="0"
21   Function="1"
22   Variable="2"
23   Typedef="3"
24   Enumeration="4"
25   EnumValue="5"
26   Signal="6"
27   Slot="7"
28   Friend="8"
29   DCOP="9"
30   Property="10"
31   Event="11"
32   File="12"
33
34 class RequestType:
35   References="9901"
36   Struct="9902"
37   Includers="9903"
38   Includees="9904"
39   Members="9905"
40   BaseClasses="9906"
41   SubClasses="9907"
42
43 g_use_regexp=False
44 ###############################################################################
45
46 # case-insensitive sqlite regexp function
47 def re_fn(expr, item):
48     reg = re.compile(expr, re.I)
49     return reg.search(item) is not None
50
51 def openDb(dbname):
52     if dbname == None:
53         dbname = "doxygen_sqlite3.db"
54
55     if not os.path.isfile(dbname):
56         raise BaseException("No such file %s" % dbname )
57
58     conn = sqlite3.connect(dbname)
59     conn.execute('PRAGMA temp_store = MEMORY;')
60     conn.row_factory = sqlite3.Row
61     conn.create_function("REGEXP", 2, re_fn)
62     return conn
63 ###############################################################################
64 class Finder:
65     def __init__(self,cn,name,row_type=str):
66         self.cn=cn
67         self.name=name
68         self.row_type=row_type
69
70     def match(self,row):
71         if self.row_type is int:
72             return " id=?"
73         else:
74             if g_use_regexp == True:
75                 return " REGEXP (?,%s)" %row
76             else:
77                 return " %s=?" %row
78
79     def fileName(self,id_file):
80         if self.cn.execute("SELECT COUNT(*) FROM files WHERE rowid=?",[id_file]).fetchone()[0] > 1:
81             print >>sys.stderr,"WARNING: non-uniq fileid [%s]. Considering only the first match." % id_file
82
83         for r in self.cn.execute("SELECT * FROM files WHERE rowid=?",[id_file]).fetchall():
84                 return r['name']
85
86         return ""
87
88     def fileId(self,name):
89         if self.cn.execute("SELECT COUNT(*) FROM files WHERE"+self.match("name"),[name]).fetchone()[0] > 1:
90             print >>sys.stderr,"WARNING: non-uniq file name [%s]. Considering only the first match." % name
91
92         for r in self.cn.execute("SELECT rowid FROM files WHERE"+self.match("name"),[name]).fetchall():
93                 return r[0]
94
95         return -1
96 ###############################################################################
97     def references(self):
98         o=[]
99         cur = self.cn.cursor()
100         cur.execute("SELECT refid FROM memberdef WHERE"+self.match("name"),[self.name])
101         refids = cur.fetchall()
102
103         if len(refids) == 0:
104             return o
105
106         refid = refids[0]['refid']
107         cur = self.cn.cursor()
108         #TODO:SELECT rowid from refids where refid=refid
109         for info in cur.execute("SELECT * FROM xrefs WHERE refid_dst LIKE '%"+refid+"%'"):
110             item={}
111             cur = self.cn.cursor()
112             for i2 in cur.execute("SELECT * FROM memberdef WHERE refid=?",[info['src']]):
113                 item['name']=i2['name']
114                 item['src']=info['src']
115                 item['file']=self.fileName(info['id_file'])
116                 item['line']=info['line']
117
118             o.append(item)
119         return o
120 ###############################################################################
121     def function(self):
122         o=[]
123         c=self.cn.execute('SELECT * FROM memberdef WHERE'+self.match("name")+' AND kind=?',[self.name,MemberType.Function])
124         for r in c.fetchall():
125             item={}
126             item['name'] = r['name']
127             item['definition'] = r['definition']
128             item['argsstring'] = r['argsstring']
129             item['file'] = self.fileName(r['id_file'])
130             item['line'] = r['line']
131             item['detaileddescription'] = r['detaileddescription']
132             o.append(item)
133         return o
134 ###############################################################################
135     def file(self):
136         o=[]
137         for r in self.cn.execute("SELECT rowid,* FROM files WHERE"+self.match("name"),[self.name]).fetchall():
138             item={}
139             item['name'] = r['name']
140             item['id'] =   r['rowid']
141             o.append(item)
142         return o
143
144 ###############################################################################
145     def macro(self):
146         o=[]
147         c=self.cn.execute('SELECT * FROM memberdef WHERE'+self.match("name")+' AND kind=?',[self.name,MemberType.Define])
148         for r in c.fetchall():
149             item={}
150             item['name'] = r['name']
151             if r['argsstring']:
152                 item['argsstring'] = r['argsstring']
153             item['definition'] = r['initializer']
154             item['file'] = self.fileName(r['id_file'])
155             item['line'] = r['line']
156             o.append(item)
157         return o
158 ###############################################################################
159     def typedef(self):
160         o=[]
161         c=self.cn.execute('SELECT * FROM memberdef WHERE'+self.match("name")+' AND kind=?',[self.name,MemberType.Typedef])
162         for r in c.fetchall():
163             item={}
164             item['name'] = r['name']
165             item['definition'] = r['definition']
166             item['file'] = self.fileName(r['id_file'])
167             item['line'] = r['line']
168             o.append(item)
169         return o
170 ###############################################################################
171     def variable(self):
172         o=[]
173         c=self.cn.execute('SELECT * FROM memberdef WHERE'+self.match("name")+' AND kind=?',[self.name,MemberType.Variable])
174         for r in c.fetchall():
175             item={}
176             item['name'] = r['name']
177             item['definition'] = r['definition']
178             item['file'] = self.fileName(r['id_file'])
179             item['line'] = r['line']
180             o.append(item)
181         return o
182 ###############################################################################
183     def params(self):
184         o=[]
185         c=self.cn.execute('SELECT id FROM memberdef WHERE'+self.match("name"),[self.name])
186         for r in c.fetchall():
187             #a=("SELECT * FROM params where id=(SELECT id_param FROM memberdef_params where id_memberdef=?",[id_memberdef])
188             item={}
189             item['id'] = r['id']
190             o.append(item)
191         return o
192 ###############################################################################
193     def struct(self):
194         o=[]
195         c=self.cn.execute('SELECT * FROM compounddef WHERE'+self.match("name"),[self.name])
196         for r in c.fetchall():
197             item={}
198             item['name'] = r['name']
199             o.append(item)
200         return o
201 ###############################################################################
202     def includers(self):
203         o=[]
204         fid = self.fileId(self.name)
205         c=self.cn.execute('SELECT * FROM includes WHERE id_dst=?',[fid])
206         for r in c.fetchall():
207             item={}
208             item['name'] = self.fileName(r['id_src'])
209             o.append(item)
210         return o
211 ###############################################################################
212     def includees(self):
213         o=[]
214         fid = self.fileId(self.name)
215         c=self.cn.execute('SELECT * FROM includes WHERE id_src=?',[fid])
216         for r in c.fetchall():
217             item={}
218             item['name'] = self.fileName(r['id_dst'])
219             o.append(item)
220         return o
221 ###############################################################################
222     def members(self):
223         o=[]
224         c=self.cn.execute('SELECT * FROM memberdef WHERE'+self.match("scope"),[self.name])
225         for r in c.fetchall():
226             item={}
227             item['name'] = r['name']
228             item['definition'] = r['definition']
229             item['argsstring'] = r['argsstring']
230             item['file'] = self.fileName(r['id_file'])
231             item['line'] = r['line']
232             #item['documentation'] = r['documentation']
233             o.append(item)
234         return o
235 ###############################################################################
236     def baseClasses(self):
237         o=[]
238         c=self.cn.execute('SELECT base FROM basecompoundref WHERE'+self.match("derived"),[self.name])
239         for r in c.fetchall():
240             item={}
241             item['name'] = r['base']
242             o.append(item)
243         return o
244 ###############################################################################
245     def subClasses(self):
246         o=[]
247         c=self.cn.execute('SELECT derived FROM basecompoundref WHERE'+self.match("base"),[self.name])
248         for r in c.fetchall():
249             item={}
250             item['name'] = r['derived']
251             o.append(item)
252         return o
253 ###############################################################################
254 def process(f,kind):
255     request_processors = {
256         MemberType.Function: f.function,
257         MemberType.File: f.file,
258         MemberType.Define:   f.macro,
259         MemberType.Variable: f.variable,
260         MemberType.Typedef:  f.typedef,
261         RequestType.References: f.references,
262         RequestType.Struct: f.struct,
263         RequestType.Includers: f.includers,
264         RequestType.Includees: f.includees,
265         RequestType.Members: f.members,
266         RequestType.BaseClasses: f.baseClasses,
267         RequestType.SubClasses: f.subClasses
268     }
269     return request_processors[kind]()
270 ###############################################################################
271 def processHref(cn,ref):
272     j={}
273
274     # is it in memberdef ?
275     table="memberdef"
276     if ( cn.execute("SELECT count(*) from %s WHERE refid=?"%table,[ref] ).fetchone()[0] > 0 ):
277         for r in cn.execute("SELECT kind,id FROM %s WHERE refid='%s'" % (table,ref) ).fetchall():
278             f=Finder(cn,r['id'],int)
279             j=process(f,str(r['kind']))
280
281     # is it in compounddef ?
282     table="compounddef"
283     if ( cn.execute("SELECT count(*) from %s WHERE refid=?"%table,[ref]).fetchone()[0] > 0 ):
284         for r in cn.execute("SELECT id FROM %s WHERE refid=?"%table,[ref] ).fetchall():
285             f=Finder(cn,r['id'],int)
286             j=process(f,RequestType.Struct)
287
288     return j
289 ###############################################################################
290 def serveCgi():
291     import cgi
292
293     print 'Content-Type: application/json\n'
294
295     fieldStorage = cgi.FieldStorage()
296     form = dict((key, fieldStorage.getvalue(key)) for key in fieldStorage.keys())
297
298     if 'href' in form:
299         ref = form['href']
300     else:
301         print '{"result": null, "error": "no refid given"}'
302         sys.exit(0)
303
304     cn=openDb('doxygen_sqlite3.db')
305
306     j = processHref(cn,ref)
307
308     print json.dumps({"result":j,"error":None})
309 ###############################################################################
310 def usage():
311   print >>sys.stderr,"""Usage: search.py [Options]
312 Options:
313     -h, --help
314     -d <D>    Use database <D> for queries.
315     -f <F>    Search for definition of function <F>.
316     -m <M>    Search for definition of macro <M>.
317     -r <F>    Search for references to function <F>.
318     -t <T>    Search for definition of type <T>.
319     -v <V>    Search for definition of variable <V>.
320     -I <I>    What files are including <I>.
321     -i <i>    What files are included by <i>.
322     -B <C>    Get the base classes of class <C>.
323     -M <C>    Get all members of class <C>.
324     -S <C>    Get the sub classes of class <C>.
325     -R        Consider the search <term> to be a regex.
326 """
327 ###############################################################################
328 def serveCli(argv):
329     try:
330         opts, args = getopt.getopt(argv, "hr:RI:i:d:f:m:t:v:H:M:B:S:F:",["help"])
331     except getopt.GetoptError:
332         usage()
333         sys.exit(1)
334
335     ref=None
336     dbname=None
337     j={}
338     global g_use_regexp
339
340     for a, o in opts:
341         if a in ('-h', '--help'):
342             usage()
343             sys.exit(0)
344         elif a in ('-d'):
345             dbname=o
346             continue
347         elif a in ('-r'):
348             kind=RequestType.References
349         elif a in ('-R'):
350             g_use_regexp=True
351             continue
352         elif a in ('-I'):
353             kind=RequestType.Includers
354         elif a in ('-i'):
355             kind=RequestType.Includees
356         elif a in ('-M'):
357             kind=RequestType.Members
358         elif a in ('-B'):
359             kind=RequestType.BaseClasses
360         elif a in ('-S'):
361             kind=RequestType.SubClasses
362         elif a in ('-f'):
363             kind=MemberType.Function
364         elif a in ('-F'):
365             kind=MemberType.File
366         elif a in ('-m'):
367             kind=MemberType.Define
368         elif a in ('-t'):
369             kind=MemberType.Typedef
370         elif a in ('-v'):
371             kind=MemberType.Variable
372         elif a in ('-H'):
373             ref = o
374
375         cn=openDb(dbname)
376         f=Finder(cn,o)
377         if ref != None:
378           j=processHref(cn,ref)
379         else:
380           j=process(f,kind)
381         print json.dumps(j,indent=4)
382
383
384 def main(argv):
385     if 'REQUEST_METHOD' in os.environ:
386         serveCgi()
387     else:
388         serveCli(argv)
389
390 if __name__ == '__main__':
391     main(sys.argv[1:])