This brings the idea of file families, each ident is identified by his family and can be referenced in compatible families. For exemple : - A Kconfig ident can be referenced in a C file but not in a Devicetree file. - A Devicetree ident is only referenced in Devicetree files. - A C ident is only referenced in C files. Kconfig idents are defined without the CONFIG_ at the beginning. We add it while indexing for an easier processing of other files. Signed-off-by: Maxime Chretien <maxime.chretien@bootlin.com>
210 lines
4.5 KiB
Python
Executable file
210 lines
4.5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
# This file is part of Elixir, a source code cross-referencer.
|
|
#
|
|
# Copyright (C) 2017 Mikaël Bouillot
|
|
# <mikael.bouillot@bootlin.com>
|
|
#
|
|
# Elixir is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Elixir is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with Elixir. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import subprocess, os
|
|
|
|
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
def script(*args):
|
|
args = (os.path.join(CURRENT_DIR, 'script.sh'),) + args
|
|
# subprocess.run was introduced in Python 3.5
|
|
# fall back to subprocess.check_output if it's not available
|
|
if hasattr(subprocess, 'run'):
|
|
p = subprocess.run(args, stdout=subprocess.PIPE)
|
|
p = p.stdout
|
|
else:
|
|
p = subprocess.check_output(args)
|
|
return p
|
|
|
|
# Invoke ./script.sh with the given arguments
|
|
# Returns the list of output lines
|
|
|
|
def scriptLines(*args):
|
|
p = script(*args)
|
|
p = p.split(b'\n')
|
|
del p[-1]
|
|
return p
|
|
|
|
def unescape(bstr):
|
|
subs = (
|
|
('\1','\n'),
|
|
)
|
|
for a,b in subs:
|
|
a = a.encode()
|
|
b = b.encode()
|
|
bstr = bstr.replace(a, b)
|
|
return bstr
|
|
|
|
# List of tokens which we don't want to consider as identifiers
|
|
# Typically for very frequent variable names and things redefined by #define
|
|
# TODO: allow to have per project blacklists
|
|
|
|
blacklist = (
|
|
b'if',
|
|
b'else',
|
|
b'endif',
|
|
b'dev',
|
|
b'i',
|
|
b'ret',
|
|
b'err',
|
|
b'flags',
|
|
b'h',
|
|
b'data',
|
|
b'const',
|
|
b'skb',
|
|
b'len',
|
|
b'name',
|
|
b'priv',
|
|
b'p',
|
|
b'val',
|
|
b'info',
|
|
b'buf',
|
|
b'rc',
|
|
b'type',
|
|
b'out',
|
|
b'cmd',
|
|
b'port',
|
|
b'size',
|
|
b'page',
|
|
b'tp',
|
|
b'pdev',
|
|
b'state',
|
|
b'addr',
|
|
b'rdev',
|
|
b'sk',
|
|
b'count',
|
|
b'hw',
|
|
b'lock',
|
|
b'error',
|
|
b'reg',
|
|
b's',
|
|
b'id',
|
|
b'tmp',
|
|
b'codec',
|
|
b'req',
|
|
b'bp',
|
|
b'c',
|
|
b'chip',
|
|
b'r',
|
|
b'n',
|
|
b'value',
|
|
b'start',
|
|
b'index',
|
|
b'res',
|
|
b'regs',
|
|
b'j',
|
|
b'base',
|
|
b'irq',
|
|
b'x',
|
|
b'net',
|
|
b'mode',
|
|
b'vcpu',
|
|
b'host',
|
|
b'spec',
|
|
b'card',
|
|
b'sb',
|
|
b'mask',
|
|
b'list',
|
|
b'ops',
|
|
b'next',
|
|
b'ctx',
|
|
b'event',
|
|
b'q',
|
|
b'attr',
|
|
b'cpu',
|
|
b'desc',
|
|
b'msg',
|
|
b't',
|
|
b'entry',
|
|
b'arg',
|
|
b'idx',
|
|
b'end',
|
|
b'root',
|
|
b'struct',
|
|
b'static',
|
|
b'define',
|
|
b'NULL',
|
|
b'sizeof',
|
|
b'status',
|
|
b'adapter',
|
|
b'inline',
|
|
b'offset',
|
|
b'failed',
|
|
b'retval',
|
|
b'buffer',
|
|
b'length',
|
|
b'result',
|
|
b'extern',
|
|
b'driver',
|
|
b'ptr',
|
|
b'return',
|
|
)
|
|
|
|
def isIdent(bstr):
|
|
if len(bstr) < 2:
|
|
return False
|
|
elif bstr in blacklist:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def autoBytes(arg):
|
|
if type(arg) is str:
|
|
arg = arg.encode()
|
|
elif type(arg) is int:
|
|
arg = str(arg).encode()
|
|
return arg
|
|
|
|
def getDataDir():
|
|
try:
|
|
dir=os.environ['LXR_DATA_DIR']
|
|
except KeyError:
|
|
print(argv[0] + ': LXR_DATA_DIR needs to be set')
|
|
exit(1)
|
|
return dir
|
|
|
|
def currentProject():
|
|
return os.path.basename(os.path.dirname(getDataDir()))
|
|
|
|
def getFileFamily(filename):
|
|
name, ext = os.path.splitext(filename)
|
|
|
|
if ext.lower() in ['.c', '.cc', '.cpp', '.c++', '.cxx', '.h', '.s'] :
|
|
return 'C' # C file family and ASM
|
|
elif ext.lower() in ['.dts', '.dtsi'] :
|
|
return 'D' # Devicetree files
|
|
elif name.lower()[:7] in ['kconfig'] and not ext.lower() in ['.rst']:
|
|
# Some files are named like Kconfig-nommu so we only check the first 7 letters
|
|
# We also exclude documentation files that can be named kconfig
|
|
return 'K' # Kconfig files
|
|
else :
|
|
return None
|
|
|
|
compatibility_list = {
|
|
'C' : ['C', 'K'],
|
|
'K' : ['K'],
|
|
'D' : ['D']
|
|
}
|
|
|
|
# Check if families are compatible
|
|
# First argument can be a list of different families
|
|
# Second argument is the key for chossing the right array in the compatibility list
|
|
def compatibleFamily(file_family, requested_family):
|
|
return any(item in file_family for item in compatibility_list[requested_family])
|