1e8f5c617SMarkus Heiser# -*- coding: utf-8; mode: python -*- 256cd8692SMarkus Heiser# pylint: disable=W0141,C0113,C0103,C0325 3e8f5c617SMarkus Heiseru""" 4e8f5c617SMarkus Heiser cdomain 5e8f5c617SMarkus Heiser ~~~~~~~ 6e8f5c617SMarkus Heiser 7e8f5c617SMarkus Heiser Replacement for the sphinx c-domain. 8e8f5c617SMarkus Heiser 9e8f5c617SMarkus Heiser :copyright: Copyright (C) 2016 Markus Heiser 10e8f5c617SMarkus Heiser :license: GPL Version 2, June 1991 see Linux/COPYING for details. 112c645cd7SMarkus Heiser 122c645cd7SMarkus Heiser List of customizations: 132c645cd7SMarkus Heiser 14556aa6d5SMarkus Heiser * Moved the *duplicate C object description* warnings for function 15556aa6d5SMarkus Heiser declarations in the nitpicky mode. See Sphinx documentation for 16556aa6d5SMarkus Heiser the config values for ``nitpick`` and ``nitpick_ignore``. 17556aa6d5SMarkus Heiser 182c645cd7SMarkus Heiser * Add option 'name' to the "c:function:" directive. With option 'name' the 192c645cd7SMarkus Heiser ref-name of a function can be modified. E.g.:: 202c645cd7SMarkus Heiser 212c645cd7SMarkus Heiser .. c:function:: int ioctl( int fd, int request ) 222c645cd7SMarkus Heiser :name: VIDIOC_LOG_STATUS 232c645cd7SMarkus Heiser 242c645cd7SMarkus Heiser The func-name (e.g. ioctl) remains in the output but the ref-name changed 252c645cd7SMarkus Heiser from 'ioctl' to 'VIDIOC_LOG_STATUS'. The function is referenced by:: 262c645cd7SMarkus Heiser 272c645cd7SMarkus Heiser * :c:func:`VIDIOC_LOG_STATUS` or 282c645cd7SMarkus Heiser * :any:`VIDIOC_LOG_STATUS` (``:any:`` needs sphinx 1.3) 2956cd8692SMarkus Heiser 3056cd8692SMarkus Heiser * Handle signatures of function-like macros well. Don't try to deduce 3156cd8692SMarkus Heiser arguments types of function-like macros. 3256cd8692SMarkus Heiser 33e8f5c617SMarkus Heiser""" 34e8f5c617SMarkus Heiser 3556cd8692SMarkus Heiserfrom docutils import nodes 362c645cd7SMarkus Heiserfrom docutils.parsers.rst import directives 372c645cd7SMarkus Heiser 38b495360eSMarkus Heiserimport sphinx 3956cd8692SMarkus Heiserfrom sphinx import addnodes 4056cd8692SMarkus Heiserfrom sphinx.domains.c import c_funcptr_sig_re, c_sig_re 41e8f5c617SMarkus Heiserfrom sphinx.domains.c import CObject as Base_CObject 42e8f5c617SMarkus Heiserfrom sphinx.domains.c import CDomain as Base_CDomain 43e8f5c617SMarkus Heiser 44e8f5c617SMarkus Heiser__version__ = '1.0' 45e8f5c617SMarkus Heiser 46b495360eSMarkus Heiser# Get Sphinx version 47*c46988aeSRémy Léonemajor, minor, patch = sphinx.version_info[:3] 48b495360eSMarkus Heiser 49e8f5c617SMarkus Heiserdef setup(app): 50e8f5c617SMarkus Heiser 51e8f5c617SMarkus Heiser app.override_domain(CDomain) 52e8f5c617SMarkus Heiser 53e8f5c617SMarkus Heiser return dict( 54e8f5c617SMarkus Heiser version = __version__, 55e8f5c617SMarkus Heiser parallel_read_safe = True, 56e8f5c617SMarkus Heiser parallel_write_safe = True 57e8f5c617SMarkus Heiser ) 58e8f5c617SMarkus Heiser 59e8f5c617SMarkus Heiserclass CObject(Base_CObject): 60e8f5c617SMarkus Heiser 61e8f5c617SMarkus Heiser """ 62e8f5c617SMarkus Heiser Description of a C language object. 63e8f5c617SMarkus Heiser """ 642c645cd7SMarkus Heiser option_spec = { 652c645cd7SMarkus Heiser "name" : directives.unchanged 662c645cd7SMarkus Heiser } 672c645cd7SMarkus Heiser 6856cd8692SMarkus Heiser def handle_func_like_macro(self, sig, signode): 6956cd8692SMarkus Heiser u"""Handles signatures of function-like macros. 7056cd8692SMarkus Heiser 7156cd8692SMarkus Heiser If the objtype is 'function' and the the signature ``sig`` is a 7256cd8692SMarkus Heiser function-like macro, the name of the macro is returned. Otherwise 7356cd8692SMarkus Heiser ``False`` is returned. """ 7456cd8692SMarkus Heiser 7556cd8692SMarkus Heiser if not self.objtype == 'function': 7656cd8692SMarkus Heiser return False 7756cd8692SMarkus Heiser 7856cd8692SMarkus Heiser m = c_funcptr_sig_re.match(sig) 7956cd8692SMarkus Heiser if m is None: 8056cd8692SMarkus Heiser m = c_sig_re.match(sig) 8156cd8692SMarkus Heiser if m is None: 8256cd8692SMarkus Heiser raise ValueError('no match') 8356cd8692SMarkus Heiser 8456cd8692SMarkus Heiser rettype, fullname, arglist, _const = m.groups() 8556cd8692SMarkus Heiser arglist = arglist.strip() 8656cd8692SMarkus Heiser if rettype or not arglist: 8756cd8692SMarkus Heiser return False 8856cd8692SMarkus Heiser 8956cd8692SMarkus Heiser arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup 9056cd8692SMarkus Heiser arglist = [a.strip() for a in arglist.split(",")] 9156cd8692SMarkus Heiser 9256cd8692SMarkus Heiser # has the first argument a type? 9356cd8692SMarkus Heiser if len(arglist[0].split(" ")) > 1: 9456cd8692SMarkus Heiser return False 9556cd8692SMarkus Heiser 9656cd8692SMarkus Heiser # This is a function-like macro, it's arguments are typeless! 9756cd8692SMarkus Heiser signode += addnodes.desc_name(fullname, fullname) 9856cd8692SMarkus Heiser paramlist = addnodes.desc_parameterlist() 9956cd8692SMarkus Heiser signode += paramlist 10056cd8692SMarkus Heiser 10156cd8692SMarkus Heiser for argname in arglist: 10256cd8692SMarkus Heiser param = addnodes.desc_parameter('', '', noemph=True) 10356cd8692SMarkus Heiser # separate by non-breaking space in the output 10456cd8692SMarkus Heiser param += nodes.emphasis(argname, argname) 10556cd8692SMarkus Heiser paramlist += param 10656cd8692SMarkus Heiser 10756cd8692SMarkus Heiser return fullname 10856cd8692SMarkus Heiser 1092c645cd7SMarkus Heiser def handle_signature(self, sig, signode): 1102c645cd7SMarkus Heiser """Transform a C signature into RST nodes.""" 11156cd8692SMarkus Heiser 11256cd8692SMarkus Heiser fullname = self.handle_func_like_macro(sig, signode) 11356cd8692SMarkus Heiser if not fullname: 1142c645cd7SMarkus Heiser fullname = super(CObject, self).handle_signature(sig, signode) 11556cd8692SMarkus Heiser 1162c645cd7SMarkus Heiser if "name" in self.options: 1172c645cd7SMarkus Heiser if self.objtype == 'function': 1182c645cd7SMarkus Heiser fullname = self.options["name"] 1192c645cd7SMarkus Heiser else: 1202c645cd7SMarkus Heiser # FIXME: handle :name: value of other declaration types? 1212c645cd7SMarkus Heiser pass 1222c645cd7SMarkus Heiser return fullname 1232c645cd7SMarkus Heiser 124556aa6d5SMarkus Heiser def add_target_and_index(self, name, sig, signode): 125556aa6d5SMarkus Heiser # for C API items we add a prefix since names are usually not qualified 126556aa6d5SMarkus Heiser # by a module name and so easily clash with e.g. section titles 127556aa6d5SMarkus Heiser targetname = 'c.' + name 128556aa6d5SMarkus Heiser if targetname not in self.state.document.ids: 129556aa6d5SMarkus Heiser signode['names'].append(targetname) 130556aa6d5SMarkus Heiser signode['ids'].append(targetname) 131556aa6d5SMarkus Heiser signode['first'] = (not self.names) 132556aa6d5SMarkus Heiser self.state.document.note_explicit_target(signode) 133556aa6d5SMarkus Heiser inv = self.env.domaindata['c']['objects'] 134556aa6d5SMarkus Heiser if (name in inv and self.env.config.nitpicky): 135556aa6d5SMarkus Heiser if self.objtype == 'function': 136556aa6d5SMarkus Heiser if ('c:func', name) not in self.env.config.nitpick_ignore: 137556aa6d5SMarkus Heiser self.state_machine.reporter.warning( 138556aa6d5SMarkus Heiser 'duplicate C object description of %s, ' % name + 139556aa6d5SMarkus Heiser 'other instance in ' + self.env.doc2path(inv[name][0]), 140556aa6d5SMarkus Heiser line=self.lineno) 141556aa6d5SMarkus Heiser inv[name] = (self.env.docname, self.objtype) 142556aa6d5SMarkus Heiser 143556aa6d5SMarkus Heiser indextext = self.get_index_text(name) 144556aa6d5SMarkus Heiser if indextext: 145b495360eSMarkus Heiser if major == 1 and minor < 4: 146b495360eSMarkus Heiser # indexnode's tuple changed in 1.4 147b495360eSMarkus Heiser # https://github.com/sphinx-doc/sphinx/commit/e6a5a3a92e938fcd75866b4227db9e0524d58f7c 148b495360eSMarkus Heiser self.indexnode['entries'].append( 149b495360eSMarkus Heiser ('single', indextext, targetname, '')) 150b495360eSMarkus Heiser else: 151b495360eSMarkus Heiser self.indexnode['entries'].append( 152b495360eSMarkus Heiser ('single', indextext, targetname, '', None)) 153e8f5c617SMarkus Heiser 154e8f5c617SMarkus Heiserclass CDomain(Base_CDomain): 155e8f5c617SMarkus Heiser 156e8f5c617SMarkus Heiser """C language domain.""" 157e8f5c617SMarkus Heiser name = 'c' 158e8f5c617SMarkus Heiser label = 'C' 159e8f5c617SMarkus Heiser directives = { 160e8f5c617SMarkus Heiser 'function': CObject, 161e8f5c617SMarkus Heiser 'member': CObject, 162e8f5c617SMarkus Heiser 'macro': CObject, 163e8f5c617SMarkus Heiser 'type': CObject, 164e8f5c617SMarkus Heiser 'var': CObject, 165e8f5c617SMarkus Heiser } 166