xref: /linux/Documentation/sphinx/cdomain.py (revision 42f6ebd827832e62a37350ffad776ea785a2486b)
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
47c46988aeSRémy Léonemajor, minor, patch = sphinx.version_info[:3]
48b495360eSMarkus Heiser
49e8f5c617SMarkus Heiserdef setup(app):
50e8f5c617SMarkus Heiser
51*42f6ebd8SMauro Carvalho Chehab    if (major == 1 and minor < 8):
52e8f5c617SMarkus Heiser        app.override_domain(CDomain)
53*42f6ebd8SMauro Carvalho Chehab    else:
54*42f6ebd8SMauro Carvalho Chehab        app.add_domain(CDomain, override=True)
55e8f5c617SMarkus Heiser
56e8f5c617SMarkus Heiser    return dict(
57e8f5c617SMarkus Heiser        version = __version__,
58e8f5c617SMarkus Heiser        parallel_read_safe = True,
59e8f5c617SMarkus Heiser        parallel_write_safe = True
60e8f5c617SMarkus Heiser    )
61e8f5c617SMarkus Heiser
62e8f5c617SMarkus Heiserclass CObject(Base_CObject):
63e8f5c617SMarkus Heiser
64e8f5c617SMarkus Heiser    """
65e8f5c617SMarkus Heiser    Description of a C language object.
66e8f5c617SMarkus Heiser    """
672c645cd7SMarkus Heiser    option_spec = {
682c645cd7SMarkus Heiser        "name" : directives.unchanged
692c645cd7SMarkus Heiser    }
702c645cd7SMarkus Heiser
7156cd8692SMarkus Heiser    def handle_func_like_macro(self, sig, signode):
7256cd8692SMarkus Heiser        u"""Handles signatures of function-like macros.
7356cd8692SMarkus Heiser
7456cd8692SMarkus Heiser        If the objtype is 'function' and the the signature ``sig`` is a
7556cd8692SMarkus Heiser        function-like macro, the name of the macro is returned. Otherwise
7656cd8692SMarkus Heiser        ``False`` is returned.  """
7756cd8692SMarkus Heiser
7856cd8692SMarkus Heiser        if not self.objtype == 'function':
7956cd8692SMarkus Heiser            return False
8056cd8692SMarkus Heiser
8156cd8692SMarkus Heiser        m = c_funcptr_sig_re.match(sig)
8256cd8692SMarkus Heiser        if m is None:
8356cd8692SMarkus Heiser            m = c_sig_re.match(sig)
8456cd8692SMarkus Heiser            if m is None:
8556cd8692SMarkus Heiser                raise ValueError('no match')
8656cd8692SMarkus Heiser
8756cd8692SMarkus Heiser        rettype, fullname, arglist, _const = m.groups()
8856cd8692SMarkus Heiser        arglist = arglist.strip()
8956cd8692SMarkus Heiser        if rettype or not arglist:
9056cd8692SMarkus Heiser            return False
9156cd8692SMarkus Heiser
9256cd8692SMarkus Heiser        arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup
9356cd8692SMarkus Heiser        arglist = [a.strip() for a in arglist.split(",")]
9456cd8692SMarkus Heiser
9556cd8692SMarkus Heiser        # has the first argument a type?
9656cd8692SMarkus Heiser        if len(arglist[0].split(" ")) > 1:
9756cd8692SMarkus Heiser            return False
9856cd8692SMarkus Heiser
9956cd8692SMarkus Heiser        # This is a function-like macro, it's arguments are typeless!
10056cd8692SMarkus Heiser        signode  += addnodes.desc_name(fullname, fullname)
10156cd8692SMarkus Heiser        paramlist = addnodes.desc_parameterlist()
10256cd8692SMarkus Heiser        signode  += paramlist
10356cd8692SMarkus Heiser
10456cd8692SMarkus Heiser        for argname in arglist:
10556cd8692SMarkus Heiser            param = addnodes.desc_parameter('', '', noemph=True)
10656cd8692SMarkus Heiser            # separate by non-breaking space in the output
10756cd8692SMarkus Heiser            param += nodes.emphasis(argname, argname)
10856cd8692SMarkus Heiser            paramlist += param
10956cd8692SMarkus Heiser
11056cd8692SMarkus Heiser        return fullname
11156cd8692SMarkus Heiser
1122c645cd7SMarkus Heiser    def handle_signature(self, sig, signode):
1132c645cd7SMarkus Heiser        """Transform a C signature into RST nodes."""
11456cd8692SMarkus Heiser
11556cd8692SMarkus Heiser        fullname = self.handle_func_like_macro(sig, signode)
11656cd8692SMarkus Heiser        if not fullname:
1172c645cd7SMarkus Heiser            fullname = super(CObject, self).handle_signature(sig, signode)
11856cd8692SMarkus Heiser
1192c645cd7SMarkus Heiser        if "name" in self.options:
1202c645cd7SMarkus Heiser            if self.objtype == 'function':
1212c645cd7SMarkus Heiser                fullname = self.options["name"]
1222c645cd7SMarkus Heiser            else:
1232c645cd7SMarkus Heiser                # FIXME: handle :name: value of other declaration types?
1242c645cd7SMarkus Heiser                pass
1252c645cd7SMarkus Heiser        return fullname
1262c645cd7SMarkus Heiser
127556aa6d5SMarkus Heiser    def add_target_and_index(self, name, sig, signode):
128556aa6d5SMarkus Heiser        # for C API items we add a prefix since names are usually not qualified
129556aa6d5SMarkus Heiser        # by a module name and so easily clash with e.g. section titles
130556aa6d5SMarkus Heiser        targetname = 'c.' + name
131556aa6d5SMarkus Heiser        if targetname not in self.state.document.ids:
132556aa6d5SMarkus Heiser            signode['names'].append(targetname)
133556aa6d5SMarkus Heiser            signode['ids'].append(targetname)
134556aa6d5SMarkus Heiser            signode['first'] = (not self.names)
135556aa6d5SMarkus Heiser            self.state.document.note_explicit_target(signode)
136556aa6d5SMarkus Heiser            inv = self.env.domaindata['c']['objects']
137556aa6d5SMarkus Heiser            if (name in inv and self.env.config.nitpicky):
138556aa6d5SMarkus Heiser                if self.objtype == 'function':
139556aa6d5SMarkus Heiser                    if ('c:func', name) not in self.env.config.nitpick_ignore:
140556aa6d5SMarkus Heiser                        self.state_machine.reporter.warning(
141556aa6d5SMarkus Heiser                            'duplicate C object description of %s, ' % name +
142556aa6d5SMarkus Heiser                            'other instance in ' + self.env.doc2path(inv[name][0]),
143556aa6d5SMarkus Heiser                            line=self.lineno)
144556aa6d5SMarkus Heiser            inv[name] = (self.env.docname, self.objtype)
145556aa6d5SMarkus Heiser
146556aa6d5SMarkus Heiser        indextext = self.get_index_text(name)
147556aa6d5SMarkus Heiser        if indextext:
148b495360eSMarkus Heiser            if major == 1 and minor < 4:
149b495360eSMarkus Heiser                # indexnode's tuple changed in 1.4
150b495360eSMarkus Heiser                # https://github.com/sphinx-doc/sphinx/commit/e6a5a3a92e938fcd75866b4227db9e0524d58f7c
151b495360eSMarkus Heiser                self.indexnode['entries'].append(
152b495360eSMarkus Heiser                    ('single', indextext, targetname, ''))
153b495360eSMarkus Heiser            else:
154b495360eSMarkus Heiser                self.indexnode['entries'].append(
155b495360eSMarkus Heiser                    ('single', indextext, targetname, '', None))
156e8f5c617SMarkus Heiser
157e8f5c617SMarkus Heiserclass CDomain(Base_CDomain):
158e8f5c617SMarkus Heiser
159e8f5c617SMarkus Heiser    """C language domain."""
160e8f5c617SMarkus Heiser    name = 'c'
161e8f5c617SMarkus Heiser    label = 'C'
162e8f5c617SMarkus Heiser    directives = {
163e8f5c617SMarkus Heiser        'function': CObject,
164e8f5c617SMarkus Heiser        'member':   CObject,
165e8f5c617SMarkus Heiser        'macro':    CObject,
166e8f5c617SMarkus Heiser        'type':     CObject,
167e8f5c617SMarkus Heiser        'var':      CObject,
168e8f5c617SMarkus Heiser    }
169