2016-08-23 00:16:21 +03:00
# -*- coding: utf-8; mode: python -*-
2016-09-07 10:12:57 +03:00
# pylint: disable=W0141,C0113,C0103,C0325
2016-08-23 00:16:21 +03:00
u """
cdomain
~ ~ ~ ~ ~ ~ ~
Replacement for the sphinx c - domain .
: copyright : Copyright ( C ) 2016 Markus Heiser
: license : GPL Version 2 , June 1991 see Linux / COPYING for details .
2016-08-15 17:08:25 +03:00
List of customizations :
doc-rst: moved *duplicate* warnings to nitpicky mode
Moved the *duplicate C object description* warnings for function
declarations in the nitpicky mode. In nitpick mode, you can suppress
those warnings (e.g. ioctl) with::
nitpicky = True
nitpick_ignore = [
("c:func", "ioctl"),
]
See Sphinx documentation for the config values for ``nitpick`` and
``nitpick_ignore`` [1].
With this change all the ".. cpp:function:: int ioctl(..)" descriptions
(found in the media book) can be migrated to ".. c:function:: int
ioctl(..)", without getting any warnings. E.g.::
.. cpp:function:: int ioctl( int fd, int request, struct cec_event *argp )
.. c:function:: int ioctl( int fd, int request, struct cec_event *argp )
The main effect, is that we get those *CPP-types* back into Sphinx's C-
namespace and we need no longer to distinguish between c/cpp references,
when we refer a function like the ioctl.
[1] http://www.sphinx-doc.org/en/stable/config.html?highlight=nitpick#confval-nitpicky
Signed-off-by: Markus Heiser <markus.heiser@darmarIT.de>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
2016-08-15 17:08:26 +03:00
* Moved the * duplicate C object description * warnings for function
declarations in the nitpicky mode . See Sphinx documentation for
the config values for ` ` nitpick ` ` and ` ` nitpick_ignore ` ` .
2016-08-15 17:08:25 +03:00
* Add option ' name ' to the " c:function: " directive . With option ' name ' the
ref - name of a function can be modified . E . g . : :
. . c : function : : int ioctl ( int fd , int request )
: name : VIDIOC_LOG_STATUS
The func - name ( e . g . ioctl ) remains in the output but the ref - name changed
from ' ioctl ' to ' VIDIOC_LOG_STATUS ' . The function is referenced by : :
* : c : func : ` VIDIOC_LOG_STATUS ` or
* : any : ` VIDIOC_LOG_STATUS ` ( ` ` : any : ` ` needs sphinx 1.3 )
2016-09-07 10:12:57 +03:00
* Handle signatures of function - like macros well . Don ' t try to deduce
arguments types of function - like macros .
2016-08-23 00:16:21 +03:00
"""
2016-09-07 10:12:57 +03:00
from docutils import nodes
2016-08-15 17:08:25 +03:00
from docutils . parsers . rst import directives
2016-09-07 10:12:56 +03:00
import sphinx
2016-09-07 10:12:57 +03:00
from sphinx import addnodes
from sphinx . domains . c import c_funcptr_sig_re , c_sig_re
2016-08-23 00:16:21 +03:00
from sphinx . domains . c import CObject as Base_CObject
from sphinx . domains . c import CDomain as Base_CDomain
2020-09-24 12:32:38 +03:00
from itertools import chain
import re
2016-08-23 00:16:21 +03:00
2020-09-24 12:32:38 +03:00
__version__ = ' 1.1 '
2016-08-23 00:16:21 +03:00
2016-09-07 10:12:56 +03:00
# Get Sphinx version
2017-03-20 18:37:49 +03:00
major , minor , patch = sphinx . version_info [ : 3 ]
2016-09-07 10:12:56 +03:00
2020-09-24 12:32:38 +03:00
# Namespace to be prepended to the full name
namespace = None
#
# Handle trivial newer c domain tags that are part of Sphinx 3.1 c domain tags
# - Store the namespace if ".. c:namespace::" tag is found
2020-09-25 14:38:27 +03:00
#
2020-09-24 12:32:38 +03:00
RE_namespace = re . compile ( r ' ^ \ s*.. \ s*c:namespace:: \ s*( \ S+) \ s*$ ' )
def markup_namespace ( match ) :
global namespace
namespace = match . group ( 1 )
return " "
2020-09-25 14:38:27 +03:00
#
# Handle c:macro for function-style declaration
#
RE_macro = re . compile ( r ' ^ \ s*.. \ s*c:macro:: \ s*( \ S+) \ s+( \ S.*) \ s*$ ' )
def markup_macro ( match ) :
return " .. c:function:: " + match . group ( 1 ) + ' ' + match . group ( 2 )
#
# Handle newer c domain tags that are evaluated as .. c:type: for
# backward-compatibility with Sphinx < 3.0
#
RE_ctype = re . compile ( r ' ^ \ s*.. \ s*c:(struct|union|enum|enumerator|alias):: \ s*(.*)$ ' )
def markup_ctype ( match ) :
return " .. c:type:: " + match . group ( 2 )
#
# Handle newer c domain tags that are evaluated as :c:type: for
# backward-compatibility with Sphinx < 3.0
#
RE_ctype_refs = re . compile ( r ' :c:(var|struct|union|enum|enumerator)::`([^ \ `]+)` ' )
def markup_ctype_refs ( match ) :
return " :c:type:` " + match . group ( 2 ) + ' ` '
#
# Simply convert :c:expr: and :c:texpr: into a literal block.
#
RE_expr = re . compile ( r ' :c:(expr|texpr):`([^ \ `]+)` ' )
def markup_c_expr ( match ) :
2023-09-12 09:07:56 +03:00
return ' \\ `` ' + match . group ( 2 ) + ' `` \\ '
2020-09-25 14:38:27 +03:00
#
# Parse Sphinx 3.x C markups, replacing them by backward-compatible ones
#
2020-09-24 12:32:38 +03:00
def c_markups ( app , docname , source ) :
result = " "
markup_func = {
RE_namespace : markup_namespace ,
2020-09-25 14:38:27 +03:00
RE_expr : markup_c_expr ,
RE_macro : markup_macro ,
RE_ctype : markup_ctype ,
RE_ctype_refs : markup_ctype_refs ,
2020-09-24 12:32:38 +03:00
}
lines = iter ( source [ 0 ] . splitlines ( True ) )
for n in lines :
match_iterators = [ regex . finditer ( n ) for regex in markup_func ]
matches = sorted ( chain ( * match_iterators ) , key = lambda m : m . start ( ) )
for m in matches :
n = n [ : m . start ( ) ] + markup_func [ m . re ] ( m ) + n [ m . end ( ) : ]
result = result + n
source [ 0 ] = result
#
# Now implements support for the cdomain namespacing logic
#
2016-08-23 00:16:21 +03:00
def setup ( app ) :
2020-09-24 12:32:38 +03:00
# Handle easy Sphinx 3.1+ simple new tags: :c:expr and .. c:namespace::
app . connect ( ' source-read ' , c_markups )
2023-12-09 02:10:17 +03:00
app . add_domain ( CDomain , override = True )
2016-08-23 00:16:21 +03:00
return dict (
version = __version__ ,
parallel_read_safe = True ,
parallel_write_safe = True
)
class CObject ( Base_CObject ) :
"""
Description of a C language object .
"""
2016-08-15 17:08:25 +03:00
option_spec = {
" name " : directives . unchanged
}
2016-09-07 10:12:57 +03:00
def handle_func_like_macro ( self , sig , signode ) :
u """ Handles signatures of function-like macros.
2023-10-18 05:30:46 +03:00
If the objtype is ' function ' and the signature ` ` sig ` ` is a
2016-09-07 10:12:57 +03:00
function - like macro , the name of the macro is returned . Otherwise
` ` False ` ` is returned . """
2020-09-24 12:32:38 +03:00
global namespace
2016-09-07 10:12:57 +03:00
if not self . objtype == ' function ' :
return False
m = c_funcptr_sig_re . match ( sig )
if m is None :
m = c_sig_re . match ( sig )
if m is None :
raise ValueError ( ' no match ' )
rettype , fullname , arglist , _const = m . groups ( )
arglist = arglist . strip ( )
if rettype or not arglist :
return False
arglist = arglist . replace ( ' ` ' , ' ' ) . replace ( ' \\ ' , ' ' ) # remove markup
arglist = [ a . strip ( ) for a in arglist . split ( " , " ) ]
# has the first argument a type?
if len ( arglist [ 0 ] . split ( " " ) ) > 1 :
return False
2023-08-15 00:28:22 +03:00
# This is a function-like macro, its arguments are typeless!
2016-09-07 10:12:57 +03:00
signode + = addnodes . desc_name ( fullname , fullname )
paramlist = addnodes . desc_parameterlist ( )
signode + = paramlist
for argname in arglist :
param = addnodes . desc_parameter ( ' ' , ' ' , noemph = True )
# separate by non-breaking space in the output
param + = nodes . emphasis ( argname , argname )
paramlist + = param
2020-09-24 12:32:38 +03:00
if namespace :
fullname = namespace + " . " + fullname
2016-09-07 10:12:57 +03:00
return fullname
2016-08-15 17:08:25 +03:00
def handle_signature ( self , sig , signode ) :
""" Transform a C signature into RST nodes. """
2016-09-07 10:12:57 +03:00
2020-09-24 12:32:38 +03:00
global namespace
2016-09-07 10:12:57 +03:00
fullname = self . handle_func_like_macro ( sig , signode )
if not fullname :
fullname = super ( CObject , self ) . handle_signature ( sig , signode )
2016-08-15 17:08:25 +03:00
if " name " in self . options :
if self . objtype == ' function ' :
fullname = self . options [ " name " ]
else :
# FIXME: handle :name: value of other declaration types?
pass
2020-09-24 12:32:38 +03:00
else :
if namespace :
fullname = namespace + " . " + fullname
2016-08-15 17:08:25 +03:00
return fullname
doc-rst: moved *duplicate* warnings to nitpicky mode
Moved the *duplicate C object description* warnings for function
declarations in the nitpicky mode. In nitpick mode, you can suppress
those warnings (e.g. ioctl) with::
nitpicky = True
nitpick_ignore = [
("c:func", "ioctl"),
]
See Sphinx documentation for the config values for ``nitpick`` and
``nitpick_ignore`` [1].
With this change all the ".. cpp:function:: int ioctl(..)" descriptions
(found in the media book) can be migrated to ".. c:function:: int
ioctl(..)", without getting any warnings. E.g.::
.. cpp:function:: int ioctl( int fd, int request, struct cec_event *argp )
.. c:function:: int ioctl( int fd, int request, struct cec_event *argp )
The main effect, is that we get those *CPP-types* back into Sphinx's C-
namespace and we need no longer to distinguish between c/cpp references,
when we refer a function like the ioctl.
[1] http://www.sphinx-doc.org/en/stable/config.html?highlight=nitpick#confval-nitpicky
Signed-off-by: Markus Heiser <markus.heiser@darmarIT.de>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
2016-08-15 17:08:26 +03:00
def add_target_and_index ( self , name , sig , signode ) :
# for C API items we add a prefix since names are usually not qualified
# by a module name and so easily clash with e.g. section titles
targetname = ' c. ' + name
if targetname not in self . state . document . ids :
signode [ ' names ' ] . append ( targetname )
signode [ ' ids ' ] . append ( targetname )
signode [ ' first ' ] = ( not self . names )
self . state . document . note_explicit_target ( signode )
inv = self . env . domaindata [ ' c ' ] [ ' objects ' ]
if ( name in inv and self . env . config . nitpicky ) :
if self . objtype == ' function ' :
if ( ' c:func ' , name ) not in self . env . config . nitpick_ignore :
self . state_machine . reporter . warning (
' duplicate C object description of %s , ' % name +
' other instance in ' + self . env . doc2path ( inv [ name ] [ 0 ] ) ,
line = self . lineno )
inv [ name ] = ( self . env . docname , self . objtype )
indextext = self . get_index_text ( name )
if indextext :
2021-02-02 02:26:25 +03:00
self . indexnode [ ' entries ' ] . append (
2016-09-07 10:12:56 +03:00
( ' single ' , indextext , targetname , ' ' , None ) )
2016-08-23 00:16:21 +03:00
class CDomain ( Base_CDomain ) :
""" C language domain. """
name = ' c '
label = ' C '
directives = {
' function ' : CObject ,
' member ' : CObject ,
' macro ' : CObject ,
' type ' : CObject ,
' var ' : CObject ,
}