Commit | Line | Data |
---|---|---|
e8f5c617 | 1 | # -*- coding: utf-8; mode: python -*- |
56cd8692 | 2 | # pylint: disable=W0141,C0113,C0103,C0325 |
e8f5c617 MH |
3 | u""" |
4 | cdomain | |
5 | ~~~~~~~ | |
6 | ||
7 | Replacement for the sphinx c-domain. | |
8 | ||
9 | :copyright: Copyright (C) 2016 Markus Heiser | |
10 | :license: GPL Version 2, June 1991 see Linux/COPYING for details. | |
2c645cd7 MH |
11 | |
12 | List of customizations: | |
13 | ||
556aa6d5 MH |
14 | * Moved the *duplicate C object description* warnings for function |
15 | declarations in the nitpicky mode. See Sphinx documentation for | |
16 | the config values for ``nitpick`` and ``nitpick_ignore``. | |
17 | ||
2c645cd7 MH |
18 | * Add option 'name' to the "c:function:" directive. With option 'name' the |
19 | ref-name of a function can be modified. E.g.:: | |
20 | ||
21 | .. c:function:: int ioctl( int fd, int request ) | |
22 | :name: VIDIOC_LOG_STATUS | |
23 | ||
24 | The func-name (e.g. ioctl) remains in the output but the ref-name changed | |
25 | from 'ioctl' to 'VIDIOC_LOG_STATUS'. The function is referenced by:: | |
26 | ||
27 | * :c:func:`VIDIOC_LOG_STATUS` or | |
28 | * :any:`VIDIOC_LOG_STATUS` (``:any:`` needs sphinx 1.3) | |
56cd8692 MH |
29 | |
30 | * Handle signatures of function-like macros well. Don't try to deduce | |
31 | arguments types of function-like macros. | |
32 | ||
e8f5c617 MH |
33 | """ |
34 | ||
56cd8692 | 35 | from docutils import nodes |
2c645cd7 MH |
36 | from docutils.parsers.rst import directives |
37 | ||
b495360e | 38 | import sphinx |
56cd8692 MH |
39 | from sphinx import addnodes |
40 | from sphinx.domains.c import c_funcptr_sig_re, c_sig_re | |
e8f5c617 MH |
41 | from sphinx.domains.c import CObject as Base_CObject |
42 | from sphinx.domains.c import CDomain as Base_CDomain | |
43 | ||
44 | __version__ = '1.0' | |
45 | ||
b495360e | 46 | # Get Sphinx version |
c46988ae | 47 | major, minor, patch = sphinx.version_info[:3] |
b495360e | 48 | |
e8f5c617 MH |
49 | def setup(app): |
50 | ||
42f6ebd8 MCC |
51 | if (major == 1 and minor < 8): |
52 | app.override_domain(CDomain) | |
53 | else: | |
54 | app.add_domain(CDomain, override=True) | |
e8f5c617 MH |
55 | |
56 | return dict( | |
57 | version = __version__, | |
58 | parallel_read_safe = True, | |
59 | parallel_write_safe = True | |
60 | ) | |
61 | ||
62 | class CObject(Base_CObject): | |
63 | ||
64 | """ | |
65 | Description of a C language object. | |
66 | """ | |
2c645cd7 MH |
67 | option_spec = { |
68 | "name" : directives.unchanged | |
69 | } | |
70 | ||
56cd8692 MH |
71 | def handle_func_like_macro(self, sig, signode): |
72 | u"""Handles signatures of function-like macros. | |
73 | ||
74 | If the objtype is 'function' and the the signature ``sig`` is a | |
75 | function-like macro, the name of the macro is returned. Otherwise | |
76 | ``False`` is returned. """ | |
77 | ||
78 | if not self.objtype == 'function': | |
79 | return False | |
80 | ||
81 | m = c_funcptr_sig_re.match(sig) | |
82 | if m is None: | |
83 | m = c_sig_re.match(sig) | |
84 | if m is None: | |
85 | raise ValueError('no match') | |
86 | ||
87 | rettype, fullname, arglist, _const = m.groups() | |
88 | arglist = arglist.strip() | |
89 | if rettype or not arglist: | |
90 | return False | |
91 | ||
92 | arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup | |
93 | arglist = [a.strip() for a in arglist.split(",")] | |
94 | ||
95 | # has the first argument a type? | |
96 | if len(arglist[0].split(" ")) > 1: | |
97 | return False | |
98 | ||
99 | # This is a function-like macro, it's arguments are typeless! | |
100 | signode += addnodes.desc_name(fullname, fullname) | |
101 | paramlist = addnodes.desc_parameterlist() | |
102 | signode += paramlist | |
103 | ||
104 | for argname in arglist: | |
105 | param = addnodes.desc_parameter('', '', noemph=True) | |
106 | # separate by non-breaking space in the output | |
107 | param += nodes.emphasis(argname, argname) | |
108 | paramlist += param | |
109 | ||
110 | return fullname | |
111 | ||
2c645cd7 MH |
112 | def handle_signature(self, sig, signode): |
113 | """Transform a C signature into RST nodes.""" | |
56cd8692 MH |
114 | |
115 | fullname = self.handle_func_like_macro(sig, signode) | |
116 | if not fullname: | |
117 | fullname = super(CObject, self).handle_signature(sig, signode) | |
118 | ||
2c645cd7 MH |
119 | if "name" in self.options: |
120 | if self.objtype == 'function': | |
121 | fullname = self.options["name"] | |
122 | else: | |
123 | # FIXME: handle :name: value of other declaration types? | |
124 | pass | |
125 | return fullname | |
126 | ||
556aa6d5 MH |
127 | def add_target_and_index(self, name, sig, signode): |
128 | # for C API items we add a prefix since names are usually not qualified | |
129 | # by a module name and so easily clash with e.g. section titles | |
130 | targetname = 'c.' + name | |
131 | if targetname not in self.state.document.ids: | |
132 | signode['names'].append(targetname) | |
133 | signode['ids'].append(targetname) | |
134 | signode['first'] = (not self.names) | |
135 | self.state.document.note_explicit_target(signode) | |
136 | inv = self.env.domaindata['c']['objects'] | |
137 | if (name in inv and self.env.config.nitpicky): | |
138 | if self.objtype == 'function': | |
139 | if ('c:func', name) not in self.env.config.nitpick_ignore: | |
140 | self.state_machine.reporter.warning( | |
141 | 'duplicate C object description of %s, ' % name + | |
142 | 'other instance in ' + self.env.doc2path(inv[name][0]), | |
143 | line=self.lineno) | |
144 | inv[name] = (self.env.docname, self.objtype) | |
145 | ||
146 | indextext = self.get_index_text(name) | |
147 | if indextext: | |
b495360e MH |
148 | if major == 1 and minor < 4: |
149 | # indexnode's tuple changed in 1.4 | |
150 | # https://github.com/sphinx-doc/sphinx/commit/e6a5a3a92e938fcd75866b4227db9e0524d58f7c | |
151 | self.indexnode['entries'].append( | |
152 | ('single', indextext, targetname, '')) | |
153 | else: | |
154 | self.indexnode['entries'].append( | |
155 | ('single', indextext, targetname, '', None)) | |
e8f5c617 MH |
156 | |
157 | class CDomain(Base_CDomain): | |
158 | ||
159 | """C language domain.""" | |
160 | name = 'c' | |
161 | label = 'C' | |
162 | directives = { | |
163 | 'function': CObject, | |
164 | 'member': CObject, | |
165 | 'macro': CObject, | |
166 | 'type': CObject, | |
167 | 'var': CObject, | |
168 | } |