diff --git a/doc/scripts/genrest.py b/doc/scripts/genrest.py index dba2cc7aad4..604deb82cd8 100755 --- a/doc/scripts/genrest.py +++ b/doc/scripts/genrest.py @@ -105,7 +105,7 @@ def init(): args = parse_args() - kconf = kconfiglib.Kconfig(args.kconfig) + kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True) out_dir = args.out_dir index_desc = args.index_desc separate_all_index = args.separate_all_index diff --git a/scripts/kconfig/kconfig.py b/scripts/kconfig/kconfig.py index c5ce3037aac..5102eeea614 100755 --- a/scripts/kconfig/kconfig.py +++ b/scripts/kconfig/kconfig.py @@ -29,7 +29,8 @@ def main(): args = parse_args() print("Parsing Kconfig tree in " + args.kconfig_root) - kconf = Kconfig(args.kconfig_root, warn_to_stderr=False) + kconf = Kconfig(args.kconfig_root, warn_to_stderr=False, + suppress_traceback=True) # Warn for assignments to undefined symbols kconf.warn_assign_undef = True diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py index 37ba501afcb..05e41abbb65 100644 --- a/scripts/kconfig/kconfiglib.py +++ b/scripts/kconfig/kconfiglib.py @@ -554,7 +554,7 @@ from glob import iglob from os.path import dirname, exists, expandvars, islink, join, realpath -VERSION = (13, 2, 0) +VERSION = (13, 5, 0) # File layout: @@ -773,8 +773,8 @@ class Kconfig(object): See Kconfig.load_config() as well. srctree: - The value of the $srctree environment variable when the configuration was - loaded, or the empty string if $srctree wasn't set. This gives nice + The value the $srctree environment variable had when the Kconfig instance + was created, or the empty string if $srctree wasn't set. This gives nice behavior with os.path.join(), which treats "" as the current directory, without adding "./". @@ -789,13 +789,22 @@ class Kconfig(object): if multiple configurations are loaded with different values for $srctree. config_prefix: - The value of the $CONFIG_ environment variable when the configuration was - loaded. This is the prefix used (and expected) on symbol names in .config - files and C headers. Defaults to "CONFIG_". Used in the same way in the C - tools. + The value the CONFIG_ environment variable had when the Kconfig instance + was created, or "CONFIG_" if CONFIG_ wasn't set. This is the prefix used + (and expected) on symbol names in .config files and C headers. Used in + the same way in the C tools. - Like for srctree, only the value of $CONFIG_ when the configuration is - loaded matters. + config_header: + The value the KCONFIG_CONFIG_HEADER environment variable had when the + Kconfig instance was created, or the empty string if + KCONFIG_CONFIG_HEADER wasn't set. This string is inserted verbatim at the + beginning of configuration files. See write_config(). + + header_header: + The value the KCONFIG_AUTOHEADER_HEADER environment variable had when the + Kconfig instance was created, or the empty string if + KCONFIG_AUTOHEADER_HEADER wasn't set. This string is inserted verbatim at + the beginning of header files. See write_autoconf(). filename/linenr: The current parsing location, for use in Python preprocessor functions. @@ -810,11 +819,13 @@ class Kconfig(object): "_warn_assign_no_prompt", "choices", "comments", + "config_header", "config_prefix", "const_syms", "defconfig_list", "defined_syms", "env_vars", + "header_header", "kconfig_filenames", "m", "menus", @@ -854,7 +865,7 @@ class Kconfig(object): # def __init__(self, filename="Kconfig", warn=True, warn_to_stderr=True, - encoding="utf-8"): + encoding="utf-8", suppress_traceback=False): """ Creates a new Kconfig object by parsing Kconfig files. Note that Kconfig files are not the same as .config files (which store @@ -919,7 +930,35 @@ class Kconfig(object): anyway. Related PEP: https://www.python.org/dev/peps/pep-0538/ + + suppress_traceback (default: False): + Helper for tools. When True, any EnvironmentError or KconfigError + generated during parsing is caught, the exception message is printed + to stderr together with the command name, and sys.exit(1) is called + (which generates SystemExit). + + This hides the Python traceback for "expected" errors like syntax + errors in Kconfig files. + + Other exceptions besides EnvironmentError and KconfigError are still + propagated when suppress_traceback is True. """ + try: + self._init(filename, warn, warn_to_stderr, encoding) + except (EnvironmentError, KconfigError) as e: + if suppress_traceback: + cmd = sys.argv[0] # Empty string if missisng + if cmd: + cmd += ": " + # Some long exception messages have extra newlines for better + # formatting when reported as an unhandled exception. Strip + # them here. + sys.exit(cmd + str(e).strip()) + raise + + def _init(self, filename, warn, warn_to_stderr, encoding): + # See __init__() + self._encoding = encoding self.srctree = os.getenv("srctree", "") @@ -943,6 +982,9 @@ class Kconfig(object): self._unset_match = _re_match(r"# {}([^ ]+) is not set".format( self.config_prefix)) + self.config_header = os.getenv("KCONFIG_CONFIG_HEADER", "") + self.header_header = os.getenv("KCONFIG_AUTOHEADER_HEADER", "") + self.syms = {} self.const_syms = {} self.defined_syms = [] @@ -1349,8 +1391,29 @@ class Kconfig(object): elif self.warn_assign_override: self._warn(msg, filename, linenr) - def write_autoconf(self, filename, - header="/* Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) */\n"): + def load_allconfig(self, filename): + """ + Helper for all*config. Loads (merges) the configuration file specified + by KCONFIG_ALLCONFIG, if any. See Documentation/kbuild/kconfig.txt in + the Linux kernel. + + Disables warnings for duplicated assignments within configuration files + for the duration of the call + (kconf.warn_assign_override/warn_assign_redun = False), and restores + the previous warning settings at the end. The KCONFIG_ALLCONFIG + configuration file is expected to override symbols. + + Exits with sys.exit() (which raises a SystemExit exception) and prints + an error to stderr if KCONFIG_ALLCONFIG is set but the configuration + file can't be opened. + + filename: + Command-specific configuration filename - "allyes.config", + "allno.config", etc. + """ + load_allconfig(self, filename) + + def write_autoconf(self, filename=None, header=None): r""" Writes out symbol values as a C header file, matching the format used by include/generated/autoconf.h in the kernel. @@ -1364,22 +1427,37 @@ class Kconfig(object): like the modification time and possibly triggering redundant work in build tools. - filename: - Self-explanatory. + filename (default: None): + Path to write header to. - header (default: "/* Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) */\n"): - Text that will be inserted verbatim at the beginning of the file. You - would usually want it enclosed in '/* */' to make it a C comment, - and include a final terminating newline. + If None (the default), the path in the environment variable + KCONFIG_AUTOHEADER is used if set, and "include/generated/autoconf.h" + otherwise. This is compatible with the C tools. + + header (default: None): + Text inserted verbatim at the beginning of the file. You would + usually want it enclosed in '/* */' to make it a C comment, and + include a trailing newline. + + If None (the default), the value of the environment variable + KCONFIG_AUTOHEADER_HEADER had when the Kconfig instance was created + will be used if it was set, and no header otherwise. See the + Kconfig.header_header attribute. """ + if filename is None: + filename = os.getenv("KCONFIG_AUTOHEADER", + "include/generated/autoconf.h") + self._write_if_changed(filename, self._autoconf_contents(header)) def _autoconf_contents(self, header): # write_autoconf() helper. Returns the contents to write as a string, - # with 'header' at the beginning. + # with 'header' or KCONFIG_AUTOHEADER_HEADER at the beginning. - # "".join()ed later - chunks = [header] + if header is None: + header = self.header_header + + chunks = [header] # "".join()ed later add = chunks.append for sym in self.unique_defined_syms: @@ -1415,9 +1493,8 @@ class Kconfig(object): return "".join(chunks) - def write_config(self, filename=None, - header="# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n", - save_old=True, verbose=None): + def write_config(self, filename=None, header=None, save_old=True, + verbose=None): r""" Writes out symbol values in the .config format. The format matches the C implementation, including ordering. @@ -1439,16 +1516,21 @@ class Kconfig(object): (OSError/IOError). KconfigError is never raised here. filename (default: None): - Filename to save configuration to (a string). + Path to write configuration to (a string). - If None (the default), the filename in the environment variable + If None (the default), the path in the environment variable KCONFIG_CONFIG is used if set, and ".config" otherwise. See standard_config_filename(). - header (default: "# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"): - Text that will be inserted verbatim at the beginning of the file. You - would usually want each line to start with '#' to make it a comment, - and include a final terminating newline. + header (default: None): + Text inserted verbatim at the beginning of the file. You would + usually want each line to start with '#' to make it a comment, and + include a trailing newline. + + if None (the default), the value of the environment variable + KCONFIG_CONFIG_HEADER had when the Kconfig instance was created will + be used if it was set, and no header otherwise. See the + Kconfig.config_header attribute. save_old (default: True): If True and already exists, a copy of it will be saved to @@ -1493,7 +1575,7 @@ class Kconfig(object): def _config_contents(self, header): # write_config() helper. Returns the contents to write as a string, - # with 'header' at the beginning. + # with 'header' or KCONFIG_CONFIG_HEADER at the beginning. # # More memory friendly would be to 'yield' the strings and # "".join(_config_contents()), but it was a bit slower on my system. @@ -1505,13 +1587,15 @@ class Kconfig(object): for sym in self.unique_defined_syms: sym._visited = False + if header is None: + header = self.config_header + + chunks = [header] # "".join()ed later + add = chunks.append + # Did we just print an '# end of ...' comment? after_end_comment = False - # "".join()ed later - chunks = [header] - add = chunks.append - node = self.top_node while 1: # Jump to the next node with an iterative tree walk @@ -1564,8 +1648,7 @@ class Kconfig(object): add("\n#\n# {}\n#\n".format(node.prompt[0])) after_end_comment = False - def write_min_config(self, filename, - header="# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"): + def write_min_config(self, filename, header=None): """ Writes out a "minimal" configuration file, omitting symbols whose value matches their default value. The format matches the one produced by @@ -1581,12 +1664,17 @@ class Kconfig(object): (OSError/IOError). KconfigError is never raised here. filename: - Self-explanatory. + Path to write minimal configuration to. - header (default: "# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)\n"): - Text that will be inserted verbatim at the beginning of the file. You - would usually want each line to start with '#' to make it a comment, - and include a final terminating newline. + header (default: None): + Text inserted verbatim at the beginning of the file. You would + usually want each line to start with '#' to make it a comment, and + include a final terminating newline. + + if None (the default), the value of the environment variable + KCONFIG_CONFIG_HEADER had when the Kconfig instance was created will + be used if it was set, and no header otherwise. See the + Kconfig.config_header attribute. Returns a string with a message saying which file got saved. This is meant to reduce boilerplate in tools, which can do e.g. @@ -1603,9 +1691,12 @@ class Kconfig(object): def _min_config_contents(self, header): # write_min_config() helper. Returns the contents to write as a string, - # with 'header' at the beginning. + # with 'header' or KCONFIG_CONFIG_HEADER at the beginning. - chunks = [header] + if header is None: + header = self.config_header + + chunks = [header] # "".join()ed later add = chunks.append for sym in self.unique_defined_syms: @@ -2122,9 +2213,9 @@ class Kconfig(object): # it's part of a different construct if self._reuse_tokens: self._reuse_tokens = False - # self._tokens_i is known to be 1 here, because _parse_properties() - # leaves it like that when it can't recognize a line (or parses - # a help text) + # self._tokens_i is known to be 1 here, because _parse_props() + # leaves it like that when it can't recognize a line (or parses a + # help text) return True # readline() returns '' over and over at EOF, which we rely on for help @@ -2141,7 +2232,7 @@ class Kconfig(object): self._tokens = self._tokenize(line) # Initialize to 1 instead of 0 to factor out code from _parse_block() - # and _parse_properties(). They immediately fetch self._tokens[0]. + # and _parse_props(). They immediately fetch self._tokens[0]. self._tokens_i = 1 return True @@ -2839,7 +2930,7 @@ class Kconfig(object): sym.nodes.append(node) - self._parse_properties(node) + self._parse_props(node) if node.is_menuconfig and not node.prompt: self._warn("the menuconfig symbol {} has no prompt" @@ -2925,7 +3016,7 @@ class Kconfig(object): self.menus.append(node) - self._parse_properties(node) + self._parse_props(node) self._parse_block(_T_ENDMENU, node, node) node.list = node.next @@ -2945,7 +3036,7 @@ class Kconfig(object): self.comments.append(node) - self._parse_properties(node) + self._parse_props(node) prev.next = prev = node @@ -2977,7 +3068,7 @@ class Kconfig(object): choice.nodes.append(node) - self._parse_properties(node) + self._parse_props(node) self._parse_block(_T_ENDCHOICE, node, node) node.list = node.next @@ -3019,7 +3110,7 @@ class Kconfig(object): return expr - def _parse_properties(self, node): + def _parse_props(self, node): # Parses and adds properties to the MenuNode 'node' (type, 'prompt', # 'default's, etc.) Properties are later copied up to symbols and # choices in a separate pass after parsing, in e.g. @@ -3045,7 +3136,7 @@ class Kconfig(object): if t0 in _TYPE_TOKENS: # Relies on '_T_BOOL is BOOL', etc., to save a conversion - self._set_type(node, t0) + self._set_type(node.item, t0) if self._tokens[1] is not None: self._parse_prompt(node) @@ -3075,7 +3166,7 @@ class Kconfig(object): self._parse_cond())) elif t0 in _DEF_TOKEN_TO_TYPE: - self._set_type(node, _DEF_TOKEN_TO_TYPE[t0]) + self._set_type(node.item, _DEF_TOKEN_TO_TYPE[t0]) node.defaults.append((self._parse_expr(False), self._parse_cond())) @@ -3176,13 +3267,15 @@ class Kconfig(object): self._reuse_tokens = True return - def _set_type(self, node, new_type): - # UNKNOWN is falsy - if node.item.orig_type and node.item.orig_type is not new_type: - self._warn("{} defined with multiple types, {} will be used" - .format(node.item.name_and_loc, TYPE_TO_STR[new_type])) + def _set_type(self, sc, new_type): + # Sets the type of 'sc' (symbol or choice) to 'new_type' - node.item.orig_type = new_type + # UNKNOWN is falsy + if sc.orig_type and sc.orig_type is not new_type: + self._warn("{} defined with multiple types, {} will be used" + .format(sc.name_and_loc, TYPE_TO_STR[new_type])) + + sc.orig_type = new_type def _parse_prompt(self, node): # 'prompt' properties override each other within a single definition of @@ -3372,7 +3465,7 @@ class Kconfig(object): # The calculated sets might be larger than necessary as we don't do any # complex analysis of the expressions. - make_depend_on = _make_depend_on # Micro-optimization + depend_on = _depend_on # Micro-optimization # Only calculate _dependents for defined symbols. Constant and # undefined symbols could theoretically be selected/implied, but it @@ -3383,29 +3476,29 @@ class Kconfig(object): # The prompt conditions for node in sym.nodes: if node.prompt: - make_depend_on(sym, node.prompt[1]) + depend_on(sym, node.prompt[1]) # The default values and their conditions for value, cond in sym.defaults: - make_depend_on(sym, value) - make_depend_on(sym, cond) + depend_on(sym, value) + depend_on(sym, cond) # The reverse and weak reverse dependencies - make_depend_on(sym, sym.rev_dep) - make_depend_on(sym, sym.weak_rev_dep) + depend_on(sym, sym.rev_dep) + depend_on(sym, sym.weak_rev_dep) # The ranges along with their conditions for low, high, cond in sym.ranges: - make_depend_on(sym, low) - make_depend_on(sym, high) - make_depend_on(sym, cond) + depend_on(sym, low) + depend_on(sym, high) + depend_on(sym, cond) # The direct dependencies. This is usually redundant, as the direct # dependencies get propagated to properties, but it's needed to get # invalidation solid for 'imply', which only checks the direct # dependencies (even if there are no properties to propagate it # to). - make_depend_on(sym, sym.direct_dep) + depend_on(sym, sym.direct_dep) # In addition to the above, choice symbols depend on the choice # they're in, but that's handled automatically since the Choice is @@ -3418,11 +3511,11 @@ class Kconfig(object): # The prompt conditions for node in choice.nodes: if node.prompt: - make_depend_on(choice, node.prompt[1]) + depend_on(choice, node.prompt[1]) # The default symbol conditions for _, cond in choice.defaults: - make_depend_on(choice, cond) + depend_on(choice, cond) def _add_choice_deps(self): # Choices also depend on the choice symbols themselves, because the @@ -3776,7 +3869,7 @@ class Kconfig(object): .format(sym.name_and_loc)) def _parse_error(self, msg): - raise KconfigError("{}couldn't parse '{}': {}".format( + raise KconfigError("{}error: couldn't parse '{}': {}".format( "" if self.filename is None else "{}:{}: ".format(self.filename, self.linenr), self._line.strip(), msg)) @@ -5295,8 +5388,8 @@ class Choice(object): self._cached_selection = _NO_CACHED_SELECTION - # is_constant is checked by _make_depend_on(). Just set it to avoid - # having to special-case choices. + # is_constant is checked by _depend_on(). Just set it to avoid having + # to special-case choices. self.is_constant = self.is_optional = False # See Kconfig._build_dep() @@ -6117,17 +6210,9 @@ def standard_kconfig(description=None): metavar="KCONFIG", default="Kconfig", nargs="?", - help="Kconfig file (default: Kconfig)") + help="Top-level Kconfig file (default: Kconfig)") - args = parser.parse_args() - - # Suppress backtraces for expected exceptions - try: - return Kconfig(args.kconfig) - except (EnvironmentError, KconfigError) as e: - # Some long exception messages have extra newlines for better - # formatting when reported as an unhandled exception. Strip them here. - sys.exit(str(e).strip()) + return Kconfig(parser.parse_args().kconfig, suppress_traceback=True) def standard_config_filename(): @@ -6143,25 +6228,9 @@ def standard_config_filename(): def load_allconfig(kconf, filename): """ - Helper for all*config. Loads (merges) the configuration file specified by - KCONFIG_ALLCONFIG, if any. See Documentation/kbuild/kconfig.txt in the - Linux kernel. - - Disables warnings for duplicated assignments within configuration files for - the duration of the call (kconf.warn_assign_override/warn_assign_redun = False), - and restores the previous warning settings at the end. The - KCONFIG_ALLCONFIG configuration file is expected to override symbols. - - Exits with sys.exit() (which raises a SystemExit exception) and prints an - error to stderr if KCONFIG_ALLCONFIG is set but the configuration file - can't be opened. - - kconf: - Kconfig instance to load the configuration in. - - filename: - Command-specific configuration filename - "allyes.config", - "allno.config", etc. + Use Kconfig.load_allconfig() instead, which was added in Kconfiglib 13.4.0. + Supported for backwards compatibility. Might be removed at some point after + a long period of deprecation warnings. """ allconfig = os.getenv("KCONFIG_ALLCONFIG") if allconfig is None: @@ -6237,7 +6306,7 @@ def _visibility(sc): return vis -def _make_depend_on(sc, expr): +def _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 # anyway. @@ -6245,11 +6314,11 @@ def _make_depend_on(sc, expr): if expr.__class__ is tuple: # AND, OR, NOT, or relation - _make_depend_on(sc, expr[1]) + _depend_on(sc, expr[1]) # NOTs only have a single operand if expr[0] is not NOT: - _make_depend_on(sc, expr[2]) + _depend_on(sc, expr[2]) elif not expr.is_constant: # Non-constant symbol, or choice diff --git a/scripts/kconfig/lint.py b/scripts/kconfig/lint.py index 321d378d67b..7a7abb3d333 100755 --- a/scripts/kconfig/lint.py +++ b/scripts/kconfig/lint.py @@ -151,7 +151,7 @@ def init_kconfig(): BOARD_DIR="boards/*/*", ARCH="*") - kconf = kconfiglib.Kconfig() + kconf = kconfiglib.Kconfig(suppress_traceback=True) def modules_file_dir(): diff --git a/scripts/kconfig/menuconfig.py b/scripts/kconfig/menuconfig.py index 6c4c62adbed..70417faa3d5 100755 --- a/scripts/kconfig/menuconfig.py +++ b/scripts/kconfig/menuconfig.py @@ -137,13 +137,16 @@ If there's an error in the style definition or if a missing style is assigned to, the assignment will be ignored, along with a warning being printed on stderr. -The 'default' theme is always implicitly parsed first (or the 'monochrome' -theme if the terminal lacks colors), so the following two settings have the -same effect: +The 'default' theme is always implicitly parsed first, so the following two +settings have the same effect: MENUCONFIG_STYLE="selection=fg:white,bg:red" MENUCONFIG_STYLE="default selection=fg:white,bg:red" +If the terminal doesn't support colors, the 'monochrome' theme is used, and +MENUCONFIG_STYLE is ignored. The assumption is that the environment is broken +somehow, and that the important thing is to get something usable. + Other features ============== @@ -182,12 +185,15 @@ See the https://github.com/zephyrproject-rtos/windows-curses repository. """ from __future__ import print_function +import os import sys +_IS_WINDOWS = os.name == "nt" # Are we running on Windows? + try: import curses except ImportError as e: - if sys.platform != "win32": + if not _IS_WINDOWS: raise sys.exit("""\ menuconfig failed to import the standard Python 'curses' library. Try @@ -206,7 +212,6 @@ Exception: import errno import locale -import os import re import textwrap @@ -312,19 +317,18 @@ _STYLES = { text= """, - # Blue tinted style loosely resembling lxdialog + # Blue-tinted style loosely resembling lxdialog "aquatic": """ path=fg:cyan,bg:blue,bold separator=fg:white,bg:cyan,bold help=path frame=fg:white,bg:cyan,bold - body=fg:brightwhite,bg:blue + body=fg:white,bg:blue edit=fg:black,bg:white """ } -# Standard colors definition -_STYLE_STD_COLORS = { +_NAMED_COLORS = { # Basic colors "black": curses.COLOR_BLACK, "red": curses.COLOR_RED, @@ -550,9 +554,6 @@ def _style_to_curses(style_def): def parse_color(color_def): color_def = color_def.split(":", 1)[1] - if color_def in _STYLE_STD_COLORS: - return _color_from_num(_STYLE_STD_COLORS[color_def]) - # HTML format, #RRGGBB if re.match("#[A-Fa-f0-9]{6}", color_def): return _color_from_rgb(( @@ -560,19 +561,20 @@ def _style_to_curses(style_def): int(color_def[3:5], 16), int(color_def[5:7], 16))) - try: - color_num = _color_from_num(int(color_def, 0)) - except ValueError: - _warn("Ignoring color ", color_def, "that's neither predefined " - "nor a number") - - return -1 + if color_def in _NAMED_COLORS: + color_num = _color_from_num(_NAMED_COLORS[color_def]) + else: + try: + color_num = _color_from_num(int(color_def, 0)) + except ValueError: + _warn("Ignoring color", color_def, "that's neither " + "predefined nor a number") + return -1 if not -1 <= color_num < curses.COLORS: _warn("Ignoring color {}, which is outside the range " "-1..curses.COLORS-1 (-1..{})" .format(color_def, curses.COLORS - 1)) - return -1 return color_num @@ -605,15 +607,26 @@ def _style_to_curses(style_def): def _init_styles(): if curses.has_colors(): - curses.use_default_colors() + try: + curses.use_default_colors() + except curses.error: + # Ignore errors on funky terminals that support colors but not + # using default colors. Worst it can do is break transparency and + # the like. Ran across this with the MSYS2/winpty setup in + # https://github.com/msys2/MINGW-packages/issues/5823, though there + # seems to be a lot of general brokenness there. + pass - # Use the 'monochrome' style template as the base on terminals without - # color - _parse_style("default" if curses.has_colors() else "monochrome", True) - - # Add any user-defined style from the environment - if "MENUCONFIG_STYLE" in os.environ: - _parse_style(os.environ["MENUCONFIG_STYLE"], False) + # Use the 'default' theme as the base, and add any user-defined style + # settings from the environment + _parse_style("default", True) + if "MENUCONFIG_STYLE" in os.environ: + _parse_style(os.environ["MENUCONFIG_STYLE"], False) + else: + # Force the 'monochrome' theme if the terminal doesn't support colors. + # MENUCONFIG_STYLE is likely to mess things up here (though any colors + # would be ignored), so ignore it. + _parse_style("monochrome", True) # color_attribs holds the color pairs we've already created, indexed by a @@ -3274,8 +3287,5 @@ def _change_c_lc_ctype_to_utf8(): return -# Are we running on Windows? -_IS_WINDOWS = os.name == "nt" - if __name__ == "__main__": _main()