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 = sphinx.version_info[:3] 50 48 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 << 126 def setup(app): 49 def setup(app): 127 50 128 # Handle easy Sphinx 3.1+ simple new tags: !! 51 if (major == 1 and minor < 8): 129 app.connect('source-read', c_markups) !! 52 app.override_domain(CDomain) 130 app.add_domain(CDomain, override=True) !! 53 else: >> 54 app.add_domain(CDomain, override=True) 131 55 132 return dict( 56 return dict( 133 version = __version__, 57 version = __version__, 134 parallel_read_safe = True, 58 parallel_read_safe = True, 135 parallel_write_safe = True 59 parallel_write_safe = True 136 ) 60 ) 137 61 138 class CObject(Base_CObject): 62 class CObject(Base_CObject): 139 63 140 """ 64 """ 141 Description of a C language object. 65 Description of a C language object. 142 """ 66 """ 143 option_spec = { 67 option_spec = { 144 "name" : directives.unchanged 68 "name" : directives.unchanged 145 } 69 } 146 70 147 def handle_func_like_macro(self, sig, sign 71 def handle_func_like_macro(self, sig, signode): 148 u"""Handles signatures of function-lik 72 u"""Handles signatures of function-like macros. 149 73 150 If the objtype is 'function' and the s !! 74 If the objtype is 'function' and the the signature ``sig`` is a 151 function-like macro, the name of the m 75 function-like macro, the name of the macro is returned. Otherwise 152 ``False`` is returned. """ 76 ``False`` is returned. """ 153 77 154 global namespace << 155 << 156 if not self.objtype == 'function': 78 if not self.objtype == 'function': 157 return False 79 return False 158 80 159 m = c_funcptr_sig_re.match(sig) 81 m = c_funcptr_sig_re.match(sig) 160 if m is None: 82 if m is None: 161 m = c_sig_re.match(sig) 83 m = c_sig_re.match(sig) 162 if m is None: 84 if m is None: 163 raise ValueError('no match') 85 raise ValueError('no match') 164 86 165 rettype, fullname, arglist, _const = m 87 rettype, fullname, arglist, _const = m.groups() 166 arglist = arglist.strip() 88 arglist = arglist.strip() 167 if rettype or not arglist: 89 if rettype or not arglist: 168 return False 90 return False 169 91 170 arglist = arglist.replace('`', '').rep 92 arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup 171 arglist = [a.strip() for a in arglist. 93 arglist = [a.strip() for a in arglist.split(",")] 172 94 173 # has the first argument a type? 95 # has the first argument a type? 174 if len(arglist[0].split(" ")) > 1: 96 if len(arglist[0].split(" ")) > 1: 175 return False 97 return False 176 98 177 # This is a function-like macro, its a !! 99 # This is a function-like macro, it's arguments are typeless! 178 signode += addnodes.desc_name(fullnam 100 signode += addnodes.desc_name(fullname, fullname) 179 paramlist = addnodes.desc_parameterlis 101 paramlist = addnodes.desc_parameterlist() 180 signode += paramlist 102 signode += paramlist 181 103 182 for argname in arglist: 104 for argname in arglist: 183 param = addnodes.desc_parameter('' 105 param = addnodes.desc_parameter('', '', noemph=True) 184 # separate by non-breaking space i 106 # separate by non-breaking space in the output 185 param += nodes.emphasis(argname, a 107 param += nodes.emphasis(argname, argname) 186 paramlist += param 108 paramlist += param 187 109 188 if namespace: << 189 fullname = namespace + "." + fulln << 190 << 191 return fullname 110 return fullname 192 111 193 def handle_signature(self, sig, signode): 112 def handle_signature(self, sig, signode): 194 """Transform a C signature into RST no 113 """Transform a C signature into RST nodes.""" 195 114 196 global namespace << 197 << 198 fullname = self.handle_func_like_macro 115 fullname = self.handle_func_like_macro(sig, signode) 199 if not fullname: 116 if not fullname: 200 fullname = super(CObject, self).ha 117 fullname = super(CObject, self).handle_signature(sig, signode) 201 118 202 if "name" in self.options: 119 if "name" in self.options: 203 if self.objtype == 'function': 120 if self.objtype == 'function': 204 fullname = self.options["name" 121 fullname = self.options["name"] 205 else: 122 else: 206 # FIXME: handle :name: value o 123 # FIXME: handle :name: value of other declaration types? 207 pass 124 pass 208 else: << 209 if namespace: << 210 fullname = namespace + "." + f << 211 << 212 return fullname 125 return fullname 213 126 214 def add_target_and_index(self, name, sig, 127 def add_target_and_index(self, name, sig, signode): 215 # for C API items we add a prefix sinc 128 # for C API items we add a prefix since names are usually not qualified 216 # by a module name and so easily clash 129 # by a module name and so easily clash with e.g. section titles 217 targetname = 'c.' + name 130 targetname = 'c.' + name 218 if targetname not in self.state.docume 131 if targetname not in self.state.document.ids: 219 signode['names'].append(targetname 132 signode['names'].append(targetname) 220 signode['ids'].append(targetname) 133 signode['ids'].append(targetname) 221 signode['first'] = (not self.names 134 signode['first'] = (not self.names) 222 self.state.document.note_explicit_ 135 self.state.document.note_explicit_target(signode) 223 inv = self.env.domaindata['c']['ob 136 inv = self.env.domaindata['c']['objects'] 224 if (name in inv and self.env.confi 137 if (name in inv and self.env.config.nitpicky): 225 if self.objtype == 'function': 138 if self.objtype == 'function': 226 if ('c:func', name) not in 139 if ('c:func', name) not in self.env.config.nitpick_ignore: 227 self.state_machine.rep 140 self.state_machine.reporter.warning( 228 'duplicate C objec 141 'duplicate C object description of %s, ' % name + 229 'other instance in 142 'other instance in ' + self.env.doc2path(inv[name][0]), 230 line=self.lineno) 143 line=self.lineno) 231 inv[name] = (self.env.docname, sel 144 inv[name] = (self.env.docname, self.objtype) 232 145 233 indextext = self.get_index_text(name) 146 indextext = self.get_index_text(name) 234 if indextext: 147 if indextext: 235 self.indexnode['entries'].append( !! 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( 236 ('single', indextext, targ 155 ('single', indextext, targetname, '', None)) 237 156 238 class CDomain(Base_CDomain): 157 class CDomain(Base_CDomain): 239 158 240 """C language domain.""" 159 """C language domain.""" 241 name = 'c' 160 name = 'c' 242 label = 'C' 161 label = 'C' 243 directives = { 162 directives = { 244 'function': CObject, 163 'function': CObject, 245 'member': CObject, 164 'member': CObject, 246 'macro': CObject, 165 'macro': CObject, 247 'type': CObject, 166 'type': CObject, 248 'var': CObject, 167 'var': CObject, 249 } 168 }
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.