summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kconfiglib.py54
1 files changed, 52 insertions, 2 deletions
diff --git a/kconfiglib.py b/kconfiglib.py
index cd1c7bd..06b0f24 100644
--- a/kconfiglib.py
+++ b/kconfiglib.py
@@ -528,6 +528,7 @@ import os
import re
import sys
+
# File layout:
#
# Public classes
@@ -537,10 +538,12 @@ import sys
# Line length: 79 columns
+
#
# Public classes
#
+
class Kconfig(object):
"""
Represents a Kconfig configuration, e.g. for x86 or ARM. This is the set of
@@ -3656,6 +3659,7 @@ class Kconfig(object):
if self._warn_for_redun_assign:
self._warn(msg, filename, linenr)
+
class Symbol(object):
"""
Represents a configuration symbol:
@@ -4591,6 +4595,7 @@ class Symbol(object):
self.kconfig._warn(msg)
+
class Choice(object):
"""
Represents a choice statement:
@@ -5036,6 +5041,7 @@ class Choice(object):
if item._cached_vis is not None:
item._rec_invalidate()
+
class MenuNode(object):
"""
Represents a menu node in the configuration. This corresponds to an entry
@@ -5386,6 +5392,7 @@ class MenuNode(object):
return "\n".join(lines)
+
class Variable(object):
"""
Represents a preprocessor variable/function.
@@ -5440,14 +5447,17 @@ class Variable(object):
"recursive" if self.is_recursive else "immediate",
self.value)
+
class KconfigError(Exception):
"Exception raised for Kconfig-related errors"
KconfigSyntaxError = KconfigError # Backwards compatibility
+
class InternalError(Exception):
"Never raised. Kept around for backwards compatibility."
+
# Workaround:
#
# If 'errno' and 'strerror' are set on IOError, then __str__() always returns
@@ -5463,10 +5473,12 @@ class _KconfigIOError(IOError):
def __str__(self):
return self.msg
+
#
# Public functions
#
+
def expr_value(expr):
"""
Evaluates the expression 'expr' to a tristate value. Returns 0 (n), 1 (m),
@@ -5523,6 +5535,7 @@ def expr_value(expr):
if rel is GREATER: return 2*(comp > 0)
return 2*(comp >= 0) # rel is GREATER_EQUAL
+
def standard_sc_expr_str(sc):
"""
Standard symbol/choice printing function. Uses plain Kconfig syntax, and
@@ -5536,6 +5549,7 @@ def standard_sc_expr_str(sc):
# Choice
return "<choice {}>".format(sc.name) if sc.name else "<choice>"
+
def expr_str(expr, sc_expr_str_fn=standard_sc_expr_str):
"""
Returns the string representation of the expression 'expr', as in a Kconfig
@@ -5579,6 +5593,7 @@ def expr_str(expr, sc_expr_str_fn=standard_sc_expr_str):
return "{} {} {}".format(sc_expr_str_fn(expr[1]), _REL_TO_STR[expr[0]],
sc_expr_str_fn(expr[2]))
+
def expr_items(expr):
"""
Returns a set() of all items (symbols and choices) that appear in the
@@ -5604,6 +5619,7 @@ def expr_items(expr):
rec(expr)
return res
+
def split_expr(expr, op):
"""
Returns a list containing the top-level AND or OR operands in the
@@ -5648,6 +5664,7 @@ def split_expr(expr, op):
rec(expr)
return res
+
def escape(s):
r"""
Escapes the string 's' in the same fashion as is done for display in
@@ -5657,8 +5674,6 @@ def escape(s):
# \ must be escaped before " to avoid double escaping
return s.replace("\\", r"\\").replace('"', r'\"')
-# unescape() helper
-_unescape_sub = re.compile(r"\\(.)").sub
def unescape(s):
r"""
@@ -5667,6 +5682,10 @@ def unescape(s):
"""
return _unescape_sub(r"\1", s)
+# unescape() helper
+_unescape_sub = re.compile(r"\\(.)").sub
+
+
def standard_kconfig():
"""
Helper for tools. Loads the top-level Kconfig specified as the first
@@ -5687,6 +5706,7 @@ def standard_kconfig():
# formatting when reported as an unhandled exception. Strip them here.
sys.exit(str(e).strip())
+
def standard_config_filename():
"""
Helper for tools. Returns the value of KCONFIG_CONFIG (which specifies the
@@ -5697,6 +5717,7 @@ def standard_config_filename():
"""
return os.environ.get("KCONFIG_CONFIG", ".config")
+
def load_allconfig(kconf, filename):
"""
Helper for all*config. Loads (merges) the configuration file specified by
@@ -5752,10 +5773,12 @@ def load_allconfig(kconf, filename):
kconf.enable_override_warnings()
kconf.enable_redun_warnings()
+
#
# Internal functions
#
+
def _visibility(sc):
# Symbols and Choices have a "visibility" that acts as an upper bound on
# the values a user can set for them, corresponding to the visibility in
@@ -5785,6 +5808,7 @@ def _visibility(sc):
return vis
+
def _make_depend_on(sc, expr):
# Adds 'sc' (symbol or choice) as a "dependee" to all symbols in 'expr'.
# Constant symbols in 'expr' are skipped as they can never change value
@@ -5803,6 +5827,7 @@ def _make_depend_on(sc, expr):
# Non-constant symbol, or choice
expr._dependents.add(sc)
+
def _parenthesize(expr, type_, sc_expr_str_fn):
# expr_str() helper. Adds parentheses around expressions of type 'type_'.
@@ -5810,6 +5835,7 @@ def _parenthesize(expr, type_, sc_expr_str_fn):
return "({})".format(expr_str(expr, sc_expr_str_fn))
return expr_str(expr, sc_expr_str_fn)
+
def _ordered_unique(lst):
# Returns 'lst' with any duplicates removed, preserving order. This hacky
# version seems to be a common idiom. It relies on short-circuit evaluation
@@ -5819,6 +5845,7 @@ def _ordered_unique(lst):
seen_add = seen.add
return [x for x in lst if x not in seen and not seen_add(x)]
+
def _is_base_n(s, n):
try:
int(s, n)
@@ -5826,11 +5853,13 @@ def _is_base_n(s, n):
except ValueError:
return False
+
def _strcmp(s1, s2):
# strcmp()-alike that returns -1, 0, or 1
return (s1 > s2) - (s1 < s2)
+
def _sym_to_num(sym):
# expr_value() helper for converting a symbol to a number. Raises
# ValueError for symbols that can't be converted.
@@ -5841,6 +5870,7 @@ def _sym_to_num(sym):
return sym.tri_value if sym.orig_type in _BOOL_TRISTATE else \
int(sym.str_value, _TYPE_TO_BASE[sym.orig_type])
+
def _touch_dep_file(sym_name):
# If sym_name is MY_SYM_NAME, touches my/sym/name.h. See the sync_deps()
# docstring.
@@ -5854,6 +5884,7 @@ def _touch_dep_file(sym_name):
os.close(os.open(
sym_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o644))
+
def _save_old(path):
# See write_config()
@@ -5880,6 +5911,7 @@ def _save_old(path):
# over e.g. if .<filename>.old happens to be a directory.
pass
+
def _decoding_error(e, filename, macro_linenr=None):
# Gives the filename and context for UnicodeDecodeError's, which are a pain
# to debug otherwise. 'e' is the UnicodeDecodeError object.
@@ -5901,6 +5933,7 @@ def _decoding_error(e, filename, macro_linenr=None):
e.object[e.start:e.end],
e.reason))
+
def _name_and_loc(sc):
# Helper for giving the symbol/choice name and location(s) in e.g. warnings
@@ -5919,6 +5952,7 @@ def _name_and_loc(sc):
# Menu manipulation
+
def _expr_depends_on(expr, sym):
# Reimplementation of expr_depends_symbol() from mconf.c. Used to determine
# if a submenu should be implicitly created. This also influences which
@@ -5946,6 +5980,7 @@ def _expr_depends_on(expr, sym):
(_expr_depends_on(expr[1], sym) or
_expr_depends_on(expr[2], sym))
+
def _auto_menu_dep(node1, node2):
# Returns True if node2 has an "automatic menu dependency" on node1. If
# node2 has a prompt, we check its condition. Otherwise, we look directly
@@ -5955,6 +5990,7 @@ def _auto_menu_dep(node1, node2):
return _expr_depends_on(node2.prompt[1] if node2.prompt else node2.dep,
node1.item)
+
def _flatten(node):
# "Flattens" menu nodes without prompts (e.g. 'if' nodes and non-visible
# symbols with children from automatic menu creation) so that their
@@ -5983,6 +6019,7 @@ def _flatten(node):
node = node.next
+
def _remove_ifs(node):
# Removes 'if' nodes (which can be recognized by MenuNode.item being None),
# which are assumed to already have been flattened. The C implementation
@@ -6008,6 +6045,7 @@ def _remove_ifs(node):
# due to tricky Python semantics. The order matters.
cur.next = cur = next
+
def _finalize_choice(node):
# Finalizes a choice, marking each symbol whose menu node has the choice as
# the parent as a choice symbol, and automatically determining types if not
@@ -6035,6 +6073,7 @@ def _finalize_choice(node):
if not sym.orig_type:
sym.orig_type = choice.orig_type
+
def _check_dep_loop_sym(sym, ignore_choice):
# Detects dependency loops using depth-first search on the dependency graph
# (which is calculated earlier in Kconfig._build_dep()).
@@ -6109,6 +6148,7 @@ def _check_dep_loop_sym(sym, ignore_choice):
# first element in it.
return (sym,)
+
def _check_dep_loop_choice(choice, skip):
if not choice._visited:
# choice._visited == 0, unvisited
@@ -6142,6 +6182,7 @@ def _check_dep_loop_choice(choice, skip):
# first element in it.
return (choice,)
+
def _found_dep_loop(loop, cur):
# Called "on the way back" when we know we have a loop
@@ -6193,23 +6234,28 @@ def _found_dep_loop(loop, cur):
# Predefined preprocessor functions
+
def _filename_fn(kconf, _):
return kconf._filename
+
def _lineno_fn(kconf, _):
return str(kconf._linenr)
+
def _info_fn(kconf, _, msg):
print("{}:{}: {}".format(kconf._filename, kconf._linenr, msg))
return ""
+
def _warning_if_fn(kconf, _, cond, msg):
if cond == "y":
kconf._warn(msg, kconf._filename, kconf._linenr)
return ""
+
def _error_if_fn(kconf, _, cond, msg):
if cond == "y":
raise KconfigError("{}:{}: {}".format(
@@ -6217,6 +6263,7 @@ def _error_if_fn(kconf, _, cond, msg):
return ""
+
def _shell_fn(kconf, _, command):
# Only import as needed, to save some startup time
import subprocess
@@ -6557,12 +6604,15 @@ _RELATIONS = frozenset((
#
# Use ASCII regex matching on Python 3. It's already the default on Python 2.
+
def _re_match(regex):
return re.compile(regex, 0 if _IS_PY2 else re.ASCII).match
+
def _re_search(regex):
return re.compile(regex, 0 if _IS_PY2 else re.ASCII).search
+
# Various regular expressions used during parsing
# The initial token on a line. Also eats leading and trailing whitespace, so