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