elixir/lib.py
Ziyue Pan 7c4886cf3c Style: fix redundant parentheses and typos
(cherry picked from commit cd89684ce633c4997b328395cc882de3ab655475)
2023-03-23 09:54:14 +01:00

243 lines
5.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
def decode(byte_object):
# decode('ascii') fails on special chars
# FIXME: major hack until we handle everything as bytestrings
try:
return byte_object.decode('utf-8')
except UnicodeDecodeError:
return byte_object.decode('iso-8859-1')
# 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'NULL',
b'__',
b'adapter',
b'addr',
b'arg',
b'attr',
b'base',
b'bp',
b'buf',
b'buffer',
b'c',
b'card',
b'char',
b'chip',
b'cmd',
b'codec',
b'const',
b'count',
b'cpu',
b'ctx',
b'data',
b'default',
b'define',
b'desc',
b'dev',
b'driver',
b'else',
b'end',
b'endif',
b'entry',
b'err',
b'error',
b'event',
b'extern',
b'failed',
b'flags',
b'h',
b'host',
b'hw',
b'i',
b'id',
b'idx',
b'if',
b'index',
b'info',
b'inline',
b'int',
b'irq',
b'j',
b'len',
b'length',
b'list',
b'lock',
b'long',
b'mask',
b'mode',
b'msg',
b'n',
b'name',
b'net',
b'next',
b'offset',
b'ops',
b'out',
b'p',
b'pdev',
b'port',
b'priv',
b'ptr',
b'q',
b'r',
b'rc',
b'rdev',
b'reg',
b'regs',
b'req',
b'res',
b'result',
b'ret',
b'return',
b'retval',
b'root',
b's',
b'sb',
b'size',
b'sizeof',
b'sk',
b'skb',
b'spec',
b'start',
b'state',
b'static',
b'status',
b'struct',
b't',
b'tmp',
b'tp',
b'type',
b'val',
b'value',
b'vcpu',
b'x'
)
def isIdent(bstr):
if (len(bstr) < 2 or
bstr in blacklist or
bstr.startswith(b'~')):
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()))
# List all families supported by Elixir
families = ['A', 'B', 'C', 'D', 'K', 'M']
def validFamily(family):
return family in families
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
elif name.lower()[:8] in ['makefile'] and not ext.lower() in ['.rst']:
return 'M' # Makefiles
else :
return None
# 1 char values are file families
# 2 chars values with a M are macros families
compatibility_list = {
'C' : ['C', 'K'],
'K' : ['K'],
'D' : ['D', 'CM'],
'M' : ['K']
}
# Check if families are compatible
# First argument can be a list of different families
# Second argument is the key for choosing 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])
# Check if a macro is compatible with the requested family
# First argument can be a list of different families
# Second argument is the key for choosing the right array in the compatibility list
def compatibleMacro(macro_family, requested_family):
result = False
for item in macro_family:
item += 'M'
result = result or item in compatibility_list[requested_family]
return result