1 # -*- coding: utf-8; mode: python -*- 1 # -*- coding: utf-8; mode: python -*- 2 # pylint: disable=W0141,C0113,C0103,C0325 2 # pylint: disable=W0141,C0113,C0103,C0325 3 u""" 3 u""" 4 cdomain 4 cdomain 5 ~~~~~~~ 5 ~~~~~~~ 6 6 7 Replacement for the sphinx c-domain. 7 Replacement for the sphinx c-domain. 8 8 9 :copyright: Copyright (C) 2016 Markus He 9 :copyright: Copyright (C) 2016 Markus Heiser 10 :license: GPL Version 2, June 1991 see 10 :license: GPL Version 2, June 1991 see Linux/COPYING for details. 11 11 12 List of customizations: 12 List of customizations: 13 13 14 * Moved the *duplicate C object descriptio 14 * Moved the *duplicate C object description* warnings for function 15 declarations in the nitpicky mode. See S 15 declarations in the nitpicky mode. See Sphinx documentation for 16 the config values for ``nitpick`` and `` 16 the config values for ``nitpick`` and ``nitpick_ignore``. 17 17 18 * Add option 'name' to the "c:function:" d 18 * Add option 'name' to the "c:function:" directive. With option 'name' the 19 ref-name of a function can be modified. 19 ref-name of a function can be modified. E.g.:: 20 20 21 .. c:function:: int ioctl( int fd, i 21 .. c:function:: int ioctl( int fd, int request ) 22 :name: VIDIOC_LOG_STATUS 22 :name: VIDIOC_LOG_STATUS 23 23 24 The func-name (e.g. ioctl) remains in th 24 The func-name (e.g. ioctl) remains in the output but the ref-name changed 25 from 'ioctl' to 'VIDIOC_LOG_STATUS'. The 25 from 'ioctl' to 'VIDIOC_LOG_STATUS'. The function is referenced by:: 26 26 27 * :c:func:`VIDIOC_LOG_STATUS` or 27 * :c:func:`VIDIOC_LOG_STATUS` or 28 * :any:`VIDIOC_LOG_STATUS` (``:any:` 28 * :any:`VIDIOC_LOG_STATUS` (``:any:`` needs sphinx 1.3) 29 29 30 * Handle signatures of function-like macr 30 * Handle signatures of function-like macros well. Don't try to deduce 31 arguments types of function-like macros 31 arguments types of function-like macros. 32 32 33 """ 33 """ 34 34 35 from docutils import nodes 35 from docutils import nodes 36 from docutils.parsers.rst import directives 36 from docutils.parsers.rst import directives 37 37 38 import sphinx 38 import sphinx 39 from sphinx import addnodes 39 from sphinx import addnodes 40 from sphinx.domains.c import c_funcptr_sig_re, 40 from sphinx.domains.c import c_funcptr_sig_re, c_sig_re 41 from sphinx.domains.c import CObject as Base_C 41 from sphinx.domains.c import CObject as Base_CObject 42 from sphinx.domains.c import CDomain as Base_C 42 from sphinx.domains.c import CDomain as Base_CDomain 43 from itertools import chain << 44 import re << 45 43 46 __version__ = '1.1' !! 44 __version__ = '1.0' 47 45 48 # Get Sphinx version 46 # Get Sphinx version 49 major, minor, patch = sphinx.version_info[:3] !! 47 major, minor, patch = map(int, sphinx.__version__.split(".")) 50 << 51 # Namespace to be prepended to the full name << 52 namespace = None << 53 << 54 # << 55 # Handle trivial newer c domain tags that are << 56 # - Store the namespace if ".. c:namespace::" << 57 # << 58 RE_namespace = re.compile(r'^\s*..\s*c:namespa << 59 << 60 def markup_namespace(match): << 61 global namespace << 62 << 63 namespace = match.group(1) << 64 << 65 return "" << 66 << 67 # << 68 # Handle c:macro for function-style declaratio << 69 # << 70 RE_macro = re.compile(r'^\s*..\s*c:macro::\s*( << 71 def markup_macro(match): << 72 return ".. c:function:: " + match.group(1) << 73 << 74 # << 75 # Handle newer c domain tags that are evaluate << 76 # backward-compatibility with Sphinx < 3.0 << 77 # << 78 RE_ctype = re.compile(r'^\s*..\s*c:(struct|uni << 79 << 80 def markup_ctype(match): << 81 return ".. c:type:: " + match.group(2) << 82 << 83 # << 84 # Handle newer c domain tags that are evaluate << 85 # backward-compatibility with Sphinx < 3.0 << 86 # << 87 RE_ctype_refs = re.compile(r':c:(var|struct|un << 88 def markup_ctype_refs(match): << 89 return ":c:type:`" + match.group(2) + '`' << 90 << 91 # << 92 # Simply convert :c:expr: and :c:texpr: into a << 93 # << 94 RE_expr = re.compile(r':c:(expr|texpr):`([^\`] << 95 def markup_c_expr(match): << 96 return '\\ ``' + match.group(2) + '``\\ ' << 97 << 98 # << 99 # Parse Sphinx 3.x C markups, replacing them b << 100 # << 101 def c_markups(app, docname, source): << 102 result = "" << 103 markup_func = { << 104 RE_namespace: markup_namespace, << 105 RE_expr: markup_c_expr, << 106 RE_macro: markup_macro, << 107 RE_ctype: markup_ctype, << 108 RE_ctype_refs: markup_ctype_refs, << 109 } << 110 << 111 lines = iter(source[0].splitlines(True)) << 112 for n in lines: << 113 match_iterators = [regex.finditer(n) f << 114 matches = sorted(chain(*match_iterator << 115 for m in matches: << 116 n = n[:m.start()] + markup_func[m. << 117 << 118 result = result + n << 119 << 120 source[0] = result << 121 << 122 # << 123 # Now implements support for the cdomain names << 124 # << 125 48 126 def setup(app): 49 def setup(app): 127 50 128 # Handle easy Sphinx 3.1+ simple new tags: !! 51 app.override_domain(CDomain) 129 app.connect('source-read', c_markups) << 130 app.add_domain(CDomain, override=True) << 131 52 132 return dict( 53 return dict( 133 version = __version__, 54 version = __version__, 134 parallel_read_safe = True, 55 parallel_read_safe = True, 135 parallel_write_safe = True 56 parallel_write_safe = True 136 ) 57 ) 137 58 138 class CObject(Base_CObject): 59 class CObject(Base_CObject): 139 60 140 """ 61 """ 141 Description of a C language object. 62 Description of a C language object. 142 """ 63 """ 143 option_spec = { 64 option_spec = { 144 "name" : directives.unchanged 65 "name" : directives.unchanged 145 } 66 } 146 67 147 def handle_func_like_macro(self, sig, sign 68 def handle_func_like_macro(self, sig, signode): 148 u"""Handles signatures of function-lik 69 u"""Handles signatures of function-like macros. 149 70 150 If the objtype is 'function' and the s !! 71 If the objtype is 'function' and the the signature ``sig`` is a 151 function-like macro, the name of the m 72 function-like macro, the name of the macro is returned. Otherwise 152 ``False`` is returned. """ 73 ``False`` is returned. """ 153 74 154 global namespace << 155 << 156 if not self.objtype == 'function': 75 if not self.objtype == 'function': 157 return False 76 return False 158 77 159 m = c_funcptr_sig_re.match(sig) 78 m = c_funcptr_sig_re.match(sig) 160 if m is None: 79 if m is None: 161 m = c_sig_re.match(sig) 80 m = c_sig_re.match(sig) 162 if m is None: 81 if m is None: 163 raise ValueError('no match') 82 raise ValueError('no match') 164 83 165 rettype, fullname, arglist, _const = m 84 rettype, fullname, arglist, _const = m.groups() 166 arglist = arglist.strip() 85 arglist = arglist.strip() 167 if rettype or not arglist: 86 if rettype or not arglist: 168 return False 87 return False 169 88 170 arglist = arglist.replace('`', '').rep 89 arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup 171 arglist = [a.strip() for a in arglist. 90 arglist = [a.strip() for a in arglist.split(",")] 172 91 173 # has the first argument a type? 92 # has the first argument a type? 174 if len(arglist[0].split(" ")) > 1: 93 if len(arglist[0].split(" ")) > 1: 175 return False 94 return False 176 95 177 # This is a function-like macro, its a !! 96 # This is a function-like macro, it's arguments are typeless! 178 signode += addnodes.desc_name(fullnam 97 signode += addnodes.desc_name(fullname, fullname) 179 paramlist = addnodes.desc_parameterlis 98 paramlist = addnodes.desc_parameterlist() 180 signode += paramlist 99 signode += paramlist 181 100 182 for argname in arglist: 101 for argname in arglist: 183 param = addnodes.desc_parameter('' 102 param = addnodes.desc_parameter('', '', noemph=True) 184 # separate by non-breaking space i 103 # separate by non-breaking space in the output 185 param += nodes.emphasis(argname, a 104 param += nodes.emphasis(argname, argname) 186 paramlist += param 105 paramlist += param 187 106 188 if namespace: << 189 fullname = namespace + "." + fulln << 190 << 191 return fullname 107 return fullname 192 108 193 def handle_signature(self, sig, signode): 109 def handle_signature(self, sig, signode): 194 """Transform a C signature into RST no 110 """Transform a C signature into RST nodes.""" 195 111 196 global namespace << 197 << 198 fullname = self.handle_func_like_macro 112 fullname = self.handle_func_like_macro(sig, signode) 199 if not fullname: 113 if not fullname: 200 fullname = super(CObject, self).ha 114 fullname = super(CObject, self).handle_signature(sig, signode) 201 115 202 if "name" in self.options: 116 if "name" in self.options: 203 if self.objtype == 'function': 117 if self.objtype == 'function': 204 fullname = self.options["name" 118 fullname = self.options["name"] 205 else: 119 else: 206 # FIXME: handle :name: value o 120 # FIXME: handle :name: value of other declaration types? 207 pass 121 pass 208 else: << 209 if namespace: << 210 fullname = namespace + "." + f << 211 << 212 return fullname 122 return fullname 213 123 214 def add_target_and_index(self, name, sig, 124 def add_target_and_index(self, name, sig, signode): 215 # for C API items we add a prefix sinc 125 # for C API items we add a prefix since names are usually not qualified 216 # by a module name and so easily clash 126 # by a module name and so easily clash with e.g. section titles 217 targetname = 'c.' + name 127 targetname = 'c.' + name 218 if targetname not in self.state.docume 128 if targetname not in self.state.document.ids: 219 signode['names'].append(targetname 129 signode['names'].append(targetname) 220 signode['ids'].append(targetname) 130 signode['ids'].append(targetname) 221 signode['first'] = (not self.names 131 signode['first'] = (not self.names) 222 self.state.document.note_explicit_ 132 self.state.document.note_explicit_target(signode) 223 inv = self.env.domaindata['c']['ob 133 inv = self.env.domaindata['c']['objects'] 224 if (name in inv and self.env.confi 134 if (name in inv and self.env.config.nitpicky): 225 if self.objtype == 'function': 135 if self.objtype == 'function': 226 if ('c:func', name) not in 136 if ('c:func', name) not in self.env.config.nitpick_ignore: 227 self.state_machine.rep 137 self.state_machine.reporter.warning( 228 'duplicate C objec 138 'duplicate C object description of %s, ' % name + 229 'other instance in 139 'other instance in ' + self.env.doc2path(inv[name][0]), 230 line=self.lineno) 140 line=self.lineno) 231 inv[name] = (self.env.docname, sel 141 inv[name] = (self.env.docname, self.objtype) 232 142 233 indextext = self.get_index_text(name) 143 indextext = self.get_index_text(name) 234 if indextext: 144 if indextext: 235 self.indexnode['entries'].append( !! 145 if major == 1 and minor < 4: >> 146 # indexnode's tuple changed in 1.4 >> 147 # https://github.com/sphinx-doc/sphinx/commit/e6a5a3a92e938fcd75866b4227db9e0524d58f7c >> 148 self.indexnode['entries'].append( >> 149 ('single', indextext, targetname, '')) >> 150 else: >> 151 self.indexnode['entries'].append( 236 ('single', indextext, targ 152 ('single', indextext, targetname, '', None)) 237 153 238 class CDomain(Base_CDomain): 154 class CDomain(Base_CDomain): 239 155 240 """C language domain.""" 156 """C language domain.""" 241 name = 'c' 157 name = 'c' 242 label = 'C' 158 label = 'C' 243 directives = { 159 directives = { 244 'function': CObject, 160 'function': CObject, 245 'member': CObject, 161 'member': CObject, 246 'macro': CObject, 162 'macro': CObject, 247 'type': CObject, 163 'type': CObject, 248 'var': CObject, 164 'var': CObject, 249 } 165 }
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.