1e8f5c617SMarkus Heiser# -*- coding: utf-8; mode: python -*- 2*56cd8692SMarkus 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) 29*56cd8692SMarkus Heiser 30*56cd8692SMarkus Heiser * Handle signatures of function-like macros well. Don't try to deduce 31*56cd8692SMarkus Heiser arguments types of function-like macros. 32*56cd8692SMarkus Heiser 33e8f5c617SMarkus Heiser""" 34e8f5c617SMarkus Heiser 35*56cd8692SMarkus Heiserfrom docutils import nodes 362c645cd7SMarkus Heiserfrom docutils.parsers.rst import directives 372c645cd7SMarkus Heiser 38b495360eSMarkus Heiserimport sphinx 39*56cd8692SMarkus Heiserfrom sphinx import addnodes 40*56cd8692SMarkus 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 47b495360eSMarkus Heisermajor, minor, patch = map(int, sphinx.__version__.split(".")) 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 68*56cd8692SMarkus Heiser def handle_func_like_macro(self, sig, signode): 69*56cd8692SMarkus Heiser u"""Handles signatures of function-like macros. 70*56cd8692SMarkus Heiser 71*56cd8692SMarkus Heiser If the objtype is 'function' and the the signature ``sig`` is a 72*56cd8692SMarkus Heiser function-like macro, the name of the macro is returned. Otherwise 73*56cd8692SMarkus Heiser ``False`` is returned. """ 74*56cd8692SMarkus Heiser 75*56cd8692SMarkus Heiser if not self.objtype == 'function': 76*56cd8692SMarkus Heiser return False 77*56cd8692SMarkus Heiser 78*56cd8692SMarkus Heiser m = c_funcptr_sig_re.match(sig) 79*56cd8692SMarkus Heiser if m is None: 80*56cd8692SMarkus Heiser m = c_sig_re.match(sig) 81*56cd8692SMarkus Heiser if m is None: 82*56cd8692SMarkus Heiser raise ValueError('no match') 83*56cd8692SMarkus Heiser 84*56cd8692SMarkus Heiser rettype, fullname, arglist, _const = m.groups() 85*56cd8692SMarkus Heiser arglist = arglist.strip() 86*56cd8692SMarkus Heiser if rettype or not arglist: 87*56cd8692SMarkus Heiser return False 88*56cd8692SMarkus Heiser 89*56cd8692SMarkus Heiser arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup 90*56cd8692SMarkus Heiser arglist = [a.strip() for a in arglist.split(",")] 91*56cd8692SMarkus Heiser 92*56cd8692SMarkus Heiser # has the first argument a type? 93*56cd8692SMarkus Heiser if len(arglist[0].split(" ")) > 1: 94*56cd8692SMarkus Heiser return False 95*56cd8692SMarkus Heiser 96*56cd8692SMarkus Heiser # This is a function-like macro, it's arguments are typeless! 97*56cd8692SMarkus Heiser signode += addnodes.desc_name(fullname, fullname) 98*56cd8692SMarkus Heiser paramlist = addnodes.desc_parameterlist() 99*56cd8692SMarkus Heiser signode += paramlist 100*56cd8692SMarkus Heiser 101*56cd8692SMarkus Heiser for argname in arglist: 102*56cd8692SMarkus Heiser param = addnodes.desc_parameter('', '', noemph=True) 103*56cd8692SMarkus Heiser # separate by non-breaking space in the output 104*56cd8692SMarkus Heiser param += nodes.emphasis(argname, argname) 105*56cd8692SMarkus Heiser paramlist += param 106*56cd8692SMarkus Heiser 107*56cd8692SMarkus Heiser return fullname 108*56cd8692SMarkus Heiser 1092c645cd7SMarkus Heiser def handle_signature(self, sig, signode): 1102c645cd7SMarkus Heiser """Transform a C signature into RST nodes.""" 111*56cd8692SMarkus Heiser 112*56cd8692SMarkus Heiser fullname = self.handle_func_like_macro(sig, signode) 113*56cd8692SMarkus Heiser if not fullname: 1142c645cd7SMarkus Heiser fullname = super(CObject, self).handle_signature(sig, signode) 115*56cd8692SMarkus 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