Commit 8639f69a61b47971dba47ab5ed72e47436729bb1

Authored by Simon Glass
1 parent ee3e520dad

genconfig.py: Print defconfig next to warnings

At present we sometimes see warnings of the form:

/tmp/tmpMA89kB:36: warning: overriding the value of CMD_SPL.
	Old value: "y", new value: "y".

This is not very useful as it does not show whch defconfig file it relates
to. Update the tool to show this.

Signed-off-by: Simon Glass <sjg@chromium.org>

Showing 2 changed files with 21 additions and 8 deletions Inline Diff

tools/buildman/kconfiglib.py
1 # 1 #
2 # SPDX-License-Identifier: ISC 2 # SPDX-License-Identifier: ISC
3 # 3 #
4 # Author: Ulf Magnusson 4 # Author: Ulf Magnusson
5 # https://github.com/ulfalizer/Kconfiglib 5 # https://github.com/ulfalizer/Kconfiglib
6 6
7 # This is Kconfiglib, a Python library for scripting, debugging, and extracting 7 # This is Kconfiglib, a Python library for scripting, debugging, and extracting
8 # information from Kconfig-based configuration systems. To view the 8 # information from Kconfig-based configuration systems. To view the
9 # documentation, run 9 # documentation, run
10 # 10 #
11 # $ pydoc kconfiglib 11 # $ pydoc kconfiglib
12 # 12 #
13 # or, if you prefer HTML, 13 # or, if you prefer HTML,
14 # 14 #
15 # $ pydoc -w kconfiglib 15 # $ pydoc -w kconfiglib
16 # 16 #
17 # The examples/ subdirectory contains examples, to be run with e.g. 17 # The examples/ subdirectory contains examples, to be run with e.g.
18 # 18 #
19 # $ make scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py 19 # $ make scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py
20 # 20 #
21 # Look in testsuite.py for the test suite. 21 # Look in testsuite.py for the test suite.
22 22
23 """ 23 """
24 Kconfiglib is a Python library for scripting and extracting information from 24 Kconfiglib is a Python library for scripting and extracting information from
25 Kconfig-based configuration systems. Features include the following: 25 Kconfig-based configuration systems. Features include the following:
26 26
27 - Symbol values and properties can be looked up and values assigned 27 - Symbol values and properties can be looked up and values assigned
28 programmatically. 28 programmatically.
29 - .config files can be read and written. 29 - .config files can be read and written.
30 - Expressions can be evaluated in the context of a Kconfig configuration. 30 - Expressions can be evaluated in the context of a Kconfig configuration.
31 - Relations between symbols can be quickly determined, such as finding all 31 - Relations between symbols can be quickly determined, such as finding all
32 symbols that reference a particular symbol. 32 symbols that reference a particular symbol.
33 - Highly compatible with the scripts/kconfig/*conf utilities. The test suite 33 - Highly compatible with the scripts/kconfig/*conf utilities. The test suite
34 automatically compares outputs between Kconfiglib and the C implementation 34 automatically compares outputs between Kconfiglib and the C implementation
35 for a large number of cases. 35 for a large number of cases.
36 36
37 For the Linux kernel, scripts are run using 37 For the Linux kernel, scripts are run using
38 38
39 $ make scriptconfig [ARCH=<arch>] SCRIPT=<path to script> [SCRIPT_ARG=<arg>] 39 $ make scriptconfig [ARCH=<arch>] SCRIPT=<path to script> [SCRIPT_ARG=<arg>]
40 40
41 Using the 'scriptconfig' target ensures that required environment variables 41 Using the 'scriptconfig' target ensures that required environment variables
42 (SRCARCH, ARCH, srctree, KERNELVERSION, etc.) are set up correctly. 42 (SRCARCH, ARCH, srctree, KERNELVERSION, etc.) are set up correctly.
43 43
44 Scripts receive the name of the Kconfig file to load in sys.argv[1]. As of 44 Scripts receive the name of the Kconfig file to load in sys.argv[1]. As of
45 Linux 4.1.0-rc5, this is always "Kconfig" from the kernel top-level directory. 45 Linux 4.1.0-rc5, this is always "Kconfig" from the kernel top-level directory.
46 If an argument is provided with SCRIPT_ARG, it appears as sys.argv[2]. 46 If an argument is provided with SCRIPT_ARG, it appears as sys.argv[2].
47 47
48 To get an interactive Python prompt with Kconfiglib preloaded and a Config 48 To get an interactive Python prompt with Kconfiglib preloaded and a Config
49 object 'c' created, run 49 object 'c' created, run
50 50
51 $ make iscriptconfig [ARCH=<arch>] 51 $ make iscriptconfig [ARCH=<arch>]
52 52
53 Kconfiglib supports both Python 2 and Python 3. For (i)scriptconfig, the Python 53 Kconfiglib supports both Python 2 and Python 3. For (i)scriptconfig, the Python
54 interpreter to use can be passed in PYTHONCMD, which defaults to 'python'. PyPy 54 interpreter to use can be passed in PYTHONCMD, which defaults to 'python'. PyPy
55 works well too, and might give a nice speedup for long-running jobs. 55 works well too, and might give a nice speedup for long-running jobs.
56 56
57 The examples/ directory contains short example scripts, which can be run with 57 The examples/ directory contains short example scripts, which can be run with
58 e.g. 58 e.g.
59 59
60 $ make scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py 60 $ make scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py
61 61
62 or 62 or
63 63
64 $ make scriptconfig SCRIPT=Kconfiglib/examples/help_grep.py SCRIPT_ARG=kernel 64 $ make scriptconfig SCRIPT=Kconfiglib/examples/help_grep.py SCRIPT_ARG=kernel
65 65
66 testsuite.py contains the test suite. See the top of the script for how to run 66 testsuite.py contains the test suite. See the top of the script for how to run
67 it. 67 it.
68 68
69 Credits: Written by Ulf "Ulfalizer" Magnusson 69 Credits: Written by Ulf "Ulfalizer" Magnusson
70 70
71 Send bug reports, suggestions and other feedback to ulfalizer a.t Google's 71 Send bug reports, suggestions and other feedback to ulfalizer a.t Google's
72 email service. Don't wrestle with internal APIs. Tell me what you need and I 72 email service. Don't wrestle with internal APIs. Tell me what you need and I
73 might add it in a safe way as a client API instead.""" 73 might add it in a safe way as a client API instead."""
74 74
75 import os 75 import os
76 import re 76 import re
77 import sys 77 import sys
78 78
79 # File layout: 79 # File layout:
80 # 80 #
81 # Public classes 81 # Public classes
82 # Public functions 82 # Public functions
83 # Internal classes 83 # Internal classes
84 # Internal functions 84 # Internal functions
85 # Internal global constants 85 # Internal global constants
86 86
87 # Line length: 79 columns 87 # Line length: 79 columns
88 88
89 # 89 #
90 # Public classes 90 # Public classes
91 # 91 #
92 92
93 class Config(object): 93 class Config(object):
94 94
95 """Represents a Kconfig configuration, e.g. for i386 or ARM. This is the 95 """Represents a Kconfig configuration, e.g. for i386 or ARM. This is the
96 set of symbols and other items appearing in the configuration together with 96 set of symbols and other items appearing in the configuration together with
97 their values. Creating any number of Config objects -- including for 97 their values. Creating any number of Config objects -- including for
98 different architectures -- is safe; Kconfiglib has no global state.""" 98 different architectures -- is safe; Kconfiglib has no global state."""
99 99
100 # 100 #
101 # Public interface 101 # Public interface
102 # 102 #
103 103
104 def __init__(self, filename="Kconfig", base_dir=None, print_warnings=True, 104 def __init__(self, filename="Kconfig", base_dir=None, print_warnings=True,
105 print_undef_assign=False): 105 print_undef_assign=False):
106 """Creates a new Config object, representing a Kconfig configuration. 106 """Creates a new Config object, representing a Kconfig configuration.
107 Raises Kconfig_Syntax_Error on syntax errors. 107 Raises Kconfig_Syntax_Error on syntax errors.
108 108
109 filename (default: "Kconfig"): The base Kconfig file of the 109 filename (default: "Kconfig"): The base Kconfig file of the
110 configuration. For the Linux kernel, you'll probably want "Kconfig" 110 configuration. For the Linux kernel, you'll probably want "Kconfig"
111 from the top-level directory, as environment variables will make 111 from the top-level directory, as environment variables will make
112 sure the right Kconfig is included from there 112 sure the right Kconfig is included from there
113 (arch/<architecture>/Kconfig). If you are using Kconfiglib via 'make 113 (arch/<architecture>/Kconfig). If you are using Kconfiglib via 'make
114 scriptconfig', the filename of the base base Kconfig file will be in 114 scriptconfig', the filename of the base base Kconfig file will be in
115 sys.argv[1]. 115 sys.argv[1].
116 116
117 base_dir (default: None): The base directory relative to which 'source' 117 base_dir (default: None): The base directory relative to which 'source'
118 statements within Kconfig files will work. For the Linux kernel this 118 statements within Kconfig files will work. For the Linux kernel this
119 should be the top-level directory of the kernel tree. $-references 119 should be the top-level directory of the kernel tree. $-references
120 to existing environment variables will be expanded. 120 to existing environment variables will be expanded.
121 121
122 If None (the default), the environment variable 'srctree' will be 122 If None (the default), the environment variable 'srctree' will be
123 used if set, and the current directory otherwise. 'srctree' is set 123 used if set, and the current directory otherwise. 'srctree' is set
124 by the Linux makefiles to the top-level kernel directory. A default 124 by the Linux makefiles to the top-level kernel directory. A default
125 of "." would not work with an alternative build directory. 125 of "." would not work with an alternative build directory.
126 126
127 print_warnings (default: True): Set to True if warnings related to this 127 print_warnings (default: True): Set to True if warnings related to this
128 configuration should be printed to stderr. This can be changed later 128 configuration should be printed to stderr. This can be changed later
129 with Config.set_print_warnings(). It is provided as a constructor 129 with Config.set_print_warnings(). It is provided as a constructor
130 argument since warnings might be generated during parsing. 130 argument since warnings might be generated during parsing.
131 131
132 print_undef_assign (default: False): Set to True if informational 132 print_undef_assign (default: False): Set to True if informational
133 messages related to assignments to undefined symbols should be 133 messages related to assignments to undefined symbols should be
134 printed to stderr for this configuration. Can be changed later with 134 printed to stderr for this configuration. Can be changed later with
135 Config.set_print_undef_assign().""" 135 Config.set_print_undef_assign()."""
136 136
137 # The set of all symbols, indexed by name (a string) 137 # The set of all symbols, indexed by name (a string)
138 self.syms = {} 138 self.syms = {}
139 # Python 2/3 compatibility hack. This is the only one needed. 139 # Python 2/3 compatibility hack. This is the only one needed.
140 if sys.version_info[0] >= 3: 140 if sys.version_info[0] >= 3:
141 self.syms_iter = self.syms.values 141 self.syms_iter = self.syms.values
142 else: 142 else:
143 self.syms_iter = self.syms.itervalues 143 self.syms_iter = self.syms.itervalues
144 144
145 # The set of all defined symbols in the configuration in the order they 145 # The set of all defined symbols in the configuration in the order they
146 # appear in the Kconfig files. This excludes the special symbols n, m, 146 # appear in the Kconfig files. This excludes the special symbols n, m,
147 # and y as well as symbols that are referenced but never defined. 147 # and y as well as symbols that are referenced but never defined.
148 self.kconfig_syms = [] 148 self.kconfig_syms = []
149 149
150 # The set of all named choices (yes, choices can have names), indexed 150 # The set of all named choices (yes, choices can have names), indexed
151 # by name (a string) 151 # by name (a string)
152 self.named_choices = {} 152 self.named_choices = {}
153 153
154 # Lists containing all choices, menus and comments in the configuration 154 # Lists containing all choices, menus and comments in the configuration
155 self.choices = [] 155 self.choices = []
156 self.menus = [] 156 self.menus = []
157 self.comments = [] 157 self.comments = []
158 158
159 def register_special_symbol(type_, name, val): 159 def register_special_symbol(type_, name, val):
160 sym = Symbol() 160 sym = Symbol()
161 sym.is_special_ = True 161 sym.is_special_ = True
162 sym.is_defined_ = True 162 sym.is_defined_ = True
163 sym.config = self 163 sym.config = self
164 sym.name = name 164 sym.name = name
165 sym.type = type_ 165 sym.type = type_
166 sym.cached_val = val 166 sym.cached_val = val
167 self.syms[name] = sym 167 self.syms[name] = sym
168 return sym 168 return sym
169 169
170 # The special symbols n, m and y, used as shorthand for "n", "m" and 170 # The special symbols n, m and y, used as shorthand for "n", "m" and
171 # "y" 171 # "y"
172 self.n = register_special_symbol(TRISTATE, "n", "n") 172 self.n = register_special_symbol(TRISTATE, "n", "n")
173 self.m = register_special_symbol(TRISTATE, "m", "m") 173 self.m = register_special_symbol(TRISTATE, "m", "m")
174 self.y = register_special_symbol(TRISTATE, "y", "y") 174 self.y = register_special_symbol(TRISTATE, "y", "y")
175 # DEFCONFIG_LIST uses this 175 # DEFCONFIG_LIST uses this
176 register_special_symbol(STRING, "UNAME_RELEASE", os.uname()[2]) 176 register_special_symbol(STRING, "UNAME_RELEASE", os.uname()[2])
177 177
178 # The symbol with "option defconfig_list" set, containing a list of 178 # The symbol with "option defconfig_list" set, containing a list of
179 # default .config files 179 # default .config files
180 self.defconfig_sym = None 180 self.defconfig_sym = None
181 181
182 # See Symbol.get_(src)arch() 182 # See Symbol.get_(src)arch()
183 self.arch = os.environ.get("ARCH") 183 self.arch = os.environ.get("ARCH")
184 self.srcarch = os.environ.get("SRCARCH") 184 self.srcarch = os.environ.get("SRCARCH")
185 185
186 # See Config.__init__(). We need this for get_defconfig_filename(). 186 # See Config.__init__(). We need this for get_defconfig_filename().
187 self.srctree = os.environ.get("srctree") 187 self.srctree = os.environ.get("srctree")
188 if self.srctree is None: 188 if self.srctree is None:
189 self.srctree = "." 189 self.srctree = "."
190 190
191 self.filename = filename 191 self.filename = filename
192 if base_dir is None: 192 if base_dir is None:
193 self.base_dir = self.srctree 193 self.base_dir = self.srctree
194 else: 194 else:
195 self.base_dir = os.path.expandvars(base_dir) 195 self.base_dir = os.path.expandvars(base_dir)
196 196
197 # The 'mainmenu' text 197 # The 'mainmenu' text
198 self.mainmenu_text = None 198 self.mainmenu_text = None
199 199
200 # The filename of the most recently loaded .config file 200 # The filename of the most recently loaded .config file
201 self.config_filename = None 201 self.config_filename = None
202 # The textual header of the most recently loaded .config, uncommented 202 # The textual header of the most recently loaded .config, uncommented
203 self.config_header = None 203 self.config_header = None
204 204
205 self.print_warnings = print_warnings 205 self.print_warnings = print_warnings
206 self.print_undef_assign = print_undef_assign 206 self.print_undef_assign = print_undef_assign
207 self._warnings = []
207 208
208 # For parsing routines that stop when finding a line belonging to a 209 # For parsing routines that stop when finding a line belonging to a
209 # different construct, these holds that line and the tokenized version 210 # different construct, these holds that line and the tokenized version
210 # of that line. The purpose is to avoid having to re-tokenize the line, 211 # of that line. The purpose is to avoid having to re-tokenize the line,
211 # which is inefficient and causes problems when recording references to 212 # which is inefficient and causes problems when recording references to
212 # symbols. 213 # symbols.
213 self.end_line = None 214 self.end_line = None
214 self.end_line_tokens = None 215 self.end_line_tokens = None
215 216
216 # See the comment in _parse_expr(). 217 # See the comment in _parse_expr().
217 self._cur_item = None 218 self._cur_item = None
218 self._line = None 219 self._line = None
219 self._filename = None 220 self._filename = None
220 self._linenr = None 221 self._linenr = None
221 self._transform_m = None 222 self._transform_m = None
222 223
223 # Parse the Kconfig files 224 # Parse the Kconfig files
224 self.top_block = self._parse_file(filename, None, None, None) 225 self.top_block = self._parse_file(filename, None, None, None)
225 226
226 # Build Symbol.dep for all symbols 227 # Build Symbol.dep for all symbols
227 self._build_dep() 228 self._build_dep()
228 229
229 def get_arch(self): 230 def get_arch(self):
230 """Returns the value the environment variable ARCH had at the time the 231 """Returns the value the environment variable ARCH had at the time the
231 Config instance was created, or None if ARCH was not set. For the 232 Config instance was created, or None if ARCH was not set. For the
232 kernel, this corresponds to the architecture being built for, with 233 kernel, this corresponds to the architecture being built for, with
233 values such as "i386" or "mips".""" 234 values such as "i386" or "mips"."""
234 return self.arch 235 return self.arch
235 236
236 def get_srcarch(self): 237 def get_srcarch(self):
237 """Returns the value the environment variable SRCARCH had at the time 238 """Returns the value the environment variable SRCARCH had at the time
238 the Config instance was created, or None if SRCARCH was not set. For 239 the Config instance was created, or None if SRCARCH was not set. For
239 the kernel, this corresponds to the particular arch/ subdirectory 240 the kernel, this corresponds to the particular arch/ subdirectory
240 containing architecture-specific code.""" 241 containing architecture-specific code."""
241 return self.srcarch 242 return self.srcarch
242 243
243 def get_srctree(self): 244 def get_srctree(self):
244 """Returns the value the environment variable srctree had at the time 245 """Returns the value the environment variable srctree had at the time
245 the Config instance was created, or None if srctree was not defined. 246 the Config instance was created, or None if srctree was not defined.
246 This variable points to the source directory and is used when building 247 This variable points to the source directory and is used when building
247 in a separate directory.""" 248 in a separate directory."""
248 return self.srctree 249 return self.srctree
249 250
250 def get_base_dir(self): 251 def get_base_dir(self):
251 """Returns the base directory relative to which 'source' statements 252 """Returns the base directory relative to which 'source' statements
252 will work, passed as an argument to Config.__init__().""" 253 will work, passed as an argument to Config.__init__()."""
253 return self.base_dir 254 return self.base_dir
254 255
255 def get_kconfig_filename(self): 256 def get_kconfig_filename(self):
256 """Returns the name of the (base) kconfig file this configuration was 257 """Returns the name of the (base) kconfig file this configuration was
257 loaded from.""" 258 loaded from."""
258 return self.filename 259 return self.filename
259 260
260 def get_config_filename(self): 261 def get_config_filename(self):
261 """Returns the filename of the most recently loaded configuration file, 262 """Returns the filename of the most recently loaded configuration file,
262 or None if no configuration has been loaded.""" 263 or None if no configuration has been loaded."""
263 return self.config_filename 264 return self.config_filename
264 265
265 def get_config_header(self): 266 def get_config_header(self):
266 """Returns the (uncommented) textual header of the .config file most 267 """Returns the (uncommented) textual header of the .config file most
267 recently loaded with load_config(). Returns None if no .config file has 268 recently loaded with load_config(). Returns None if no .config file has
268 been loaded or if the most recently loaded .config file has no header. 269 been loaded or if the most recently loaded .config file has no header.
269 The header consists of all lines up to but not including the first line 270 The header consists of all lines up to but not including the first line
270 that either 271 that either
271 272
272 1. Does not start with "#" 273 1. Does not start with "#"
273 2. Has the form "# CONFIG_FOO is not set." 274 2. Has the form "# CONFIG_FOO is not set."
274 """ 275 """
275 return self.config_header 276 return self.config_header
276 277
277 def get_mainmenu_text(self): 278 def get_mainmenu_text(self):
278 """Returns the text of the 'mainmenu' statement (with $-references to 279 """Returns the text of the 'mainmenu' statement (with $-references to
279 symbols replaced by symbol values), or None if the configuration has no 280 symbols replaced by symbol values), or None if the configuration has no
280 'mainmenu' statement.""" 281 'mainmenu' statement."""
281 return None if self.mainmenu_text is None else \ 282 return None if self.mainmenu_text is None else \
282 self._expand_sym_refs(self.mainmenu_text) 283 self._expand_sym_refs(self.mainmenu_text)
283 284
284 def get_defconfig_filename(self): 285 def get_defconfig_filename(self):
285 """Returns the name of the defconfig file, which is the first existing 286 """Returns the name of the defconfig file, which is the first existing
286 file in the list given in a symbol having 'option defconfig_list' set. 287 file in the list given in a symbol having 'option defconfig_list' set.
287 $-references to symbols will be expanded ("$FOO bar" -> "foo bar" if 288 $-references to symbols will be expanded ("$FOO bar" -> "foo bar" if
288 FOO has the value "foo"). Returns None in case of no defconfig file. 289 FOO has the value "foo"). Returns None in case of no defconfig file.
289 Setting 'option defconfig_list' on multiple symbols currently results 290 Setting 'option defconfig_list' on multiple symbols currently results
290 in undefined behavior. 291 in undefined behavior.
291 292
292 If the environment variable 'srctree' was set when the Config was 293 If the environment variable 'srctree' was set when the Config was
293 created, get_defconfig_filename() will first look relative to that 294 created, get_defconfig_filename() will first look relative to that
294 directory before looking in the current directory; see 295 directory before looking in the current directory; see
295 Config.__init__(). 296 Config.__init__().
296 297
297 WARNING: A wart here is that scripts/kconfig/Makefile sometimes uses 298 WARNING: A wart here is that scripts/kconfig/Makefile sometimes uses
298 the --defconfig=<defconfig> option when calling the C implementation of 299 the --defconfig=<defconfig> option when calling the C implementation of
299 e.g. 'make defconfig'. This option overrides the 'option 300 e.g. 'make defconfig'. This option overrides the 'option
300 defconfig_list' symbol, meaning the result from 301 defconfig_list' symbol, meaning the result from
301 get_defconfig_filename() might not match what 'make defconfig' would 302 get_defconfig_filename() might not match what 'make defconfig' would
302 use. That probably ought to be worked around somehow, so that this 303 use. That probably ought to be worked around somehow, so that this
303 function always gives the "expected" result.""" 304 function always gives the "expected" result."""
304 if self.defconfig_sym is None: 305 if self.defconfig_sym is None:
305 return None 306 return None
306 for filename, cond_expr in self.defconfig_sym.def_exprs: 307 for filename, cond_expr in self.defconfig_sym.def_exprs:
307 if self._eval_expr(cond_expr) == "y": 308 if self._eval_expr(cond_expr) == "y":
308 filename = self._expand_sym_refs(filename) 309 filename = self._expand_sym_refs(filename)
309 # We first look in $srctree. os.path.join() won't work here as 310 # We first look in $srctree. os.path.join() won't work here as
310 # an absolute path in filename would override $srctree. 311 # an absolute path in filename would override $srctree.
311 srctree_filename = os.path.normpath(self.srctree + "/" + 312 srctree_filename = os.path.normpath(self.srctree + "/" +
312 filename) 313 filename)
313 if os.path.exists(srctree_filename): 314 if os.path.exists(srctree_filename):
314 return srctree_filename 315 return srctree_filename
315 if os.path.exists(filename): 316 if os.path.exists(filename):
316 return filename 317 return filename
317 return None 318 return None
318 319
319 def get_symbol(self, name): 320 def get_symbol(self, name):
320 """Returns the symbol with name 'name', or None if no such symbol 321 """Returns the symbol with name 'name', or None if no such symbol
321 appears in the configuration. An alternative shorthand is conf[name], 322 appears in the configuration. An alternative shorthand is conf[name],
322 where conf is a Config instance, though that will instead raise 323 where conf is a Config instance, though that will instead raise
323 KeyError if the symbol does not exist.""" 324 KeyError if the symbol does not exist."""
324 return self.syms.get(name) 325 return self.syms.get(name)
325 326
326 def __getitem__(self, name): 327 def __getitem__(self, name):
327 """Returns the symbol with name 'name'. Raises KeyError if the symbol 328 """Returns the symbol with name 'name'. Raises KeyError if the symbol
328 does not appear in the configuration.""" 329 does not appear in the configuration."""
329 return self.syms[name] 330 return self.syms[name]
330 331
331 def get_symbols(self, all_symbols=True): 332 def get_symbols(self, all_symbols=True):
332 """Returns a list of symbols from the configuration. An alternative for 333 """Returns a list of symbols from the configuration. An alternative for
333 iterating over all defined symbols (in the order of definition) is 334 iterating over all defined symbols (in the order of definition) is
334 335
335 for sym in config: 336 for sym in config:
336 ... 337 ...
337 338
338 which relies on Config implementing __iter__() and is equivalent to 339 which relies on Config implementing __iter__() and is equivalent to
339 340
340 for sym in config.get_symbols(False): 341 for sym in config.get_symbols(False):
341 ... 342 ...
342 343
343 all_symbols (default: True): If True, all symbols -- including special 344 all_symbols (default: True): If True, all symbols -- including special
344 and undefined symbols -- will be included in the result, in an 345 and undefined symbols -- will be included in the result, in an
345 undefined order. If False, only symbols actually defined and not 346 undefined order. If False, only symbols actually defined and not
346 merely referred to in the configuration will be included in the 347 merely referred to in the configuration will be included in the
347 result, and will appear in the order that they are defined within 348 result, and will appear in the order that they are defined within
348 the Kconfig configuration files.""" 349 the Kconfig configuration files."""
349 return list(self.syms.values()) if all_symbols else self.kconfig_syms 350 return list(self.syms.values()) if all_symbols else self.kconfig_syms
350 351
351 def __iter__(self): 352 def __iter__(self):
352 """Convenience function for iterating over the set of all defined 353 """Convenience function for iterating over the set of all defined
353 symbols in the configuration, used like 354 symbols in the configuration, used like
354 355
355 for sym in conf: 356 for sym in conf:
356 ... 357 ...
357 358
358 The iteration happens in the order of definition within the Kconfig 359 The iteration happens in the order of definition within the Kconfig
359 configuration files. Symbols only referred to but not defined will not 360 configuration files. Symbols only referred to but not defined will not
360 be included, nor will the special symbols n, m, and y. If you want to 361 be included, nor will the special symbols n, m, and y. If you want to
361 include such symbols as well, see config.get_symbols().""" 362 include such symbols as well, see config.get_symbols()."""
362 return iter(self.kconfig_syms) 363 return iter(self.kconfig_syms)
363 364
364 def get_choices(self): 365 def get_choices(self):
365 """Returns a list containing all choice statements in the 366 """Returns a list containing all choice statements in the
366 configuration, in the order they appear in the Kconfig files.""" 367 configuration, in the order they appear in the Kconfig files."""
367 return self.choices 368 return self.choices
368 369
369 def get_menus(self): 370 def get_menus(self):
370 """Returns a list containing all menus in the configuration, in the 371 """Returns a list containing all menus in the configuration, in the
371 order they appear in the Kconfig files.""" 372 order they appear in the Kconfig files."""
372 return self.menus 373 return self.menus
373 374
374 def get_comments(self): 375 def get_comments(self):
375 """Returns a list containing all comments in the configuration, in the 376 """Returns a list containing all comments in the configuration, in the
376 order they appear in the Kconfig files.""" 377 order they appear in the Kconfig files."""
377 return self.comments 378 return self.comments
378 379
379 def get_top_level_items(self): 380 def get_top_level_items(self):
380 """Returns a list containing the items (symbols, menus, choices, and 381 """Returns a list containing the items (symbols, menus, choices, and
381 comments) at the top level of the configuration -- that is, all items 382 comments) at the top level of the configuration -- that is, all items
382 that do not appear within a menu or choice. The items appear in the 383 that do not appear within a menu or choice. The items appear in the
383 same order as within the configuration.""" 384 same order as within the configuration."""
384 return self.top_block 385 return self.top_block
385 386
386 def load_config(self, filename, replace=True): 387 def load_config(self, filename, replace=True):
387 """Loads symbol values from a file in the familiar .config format. 388 """Loads symbol values from a file in the familiar .config format.
388 Equivalent to calling Symbol.set_user_value() to set each of the 389 Equivalent to calling Symbol.set_user_value() to set each of the
389 values. 390 values.
390 391
391 "# CONFIG_FOO is not set" within a .config file is treated specially 392 "# CONFIG_FOO is not set" within a .config file is treated specially
392 and sets the user value of FOO to 'n'. The C implementation works the 393 and sets the user value of FOO to 'n'. The C implementation works the
393 same way. 394 same way.
394 395
395 filename: The .config file to load. $-references to existing 396 filename: The .config file to load. $-references to existing
396 environment variables will be expanded. For scripts to work even when 397 environment variables will be expanded. For scripts to work even when
397 an alternative build directory is used with the Linux kernel, you 398 an alternative build directory is used with the Linux kernel, you
398 need to refer to the top-level kernel directory with "$srctree". 399 need to refer to the top-level kernel directory with "$srctree".
399 400
400 replace (default: True): True if the configuration should replace the 401 replace (default: True): True if the configuration should replace the
401 old configuration; False if it should add to it.""" 402 old configuration; False if it should add to it.
402 403
404 Returns a list or warnings (hopefully empty)
405 """
406
407 self._warnings = []
403 # Put this first so that a missing file doesn't screw up our state 408 # Put this first so that a missing file doesn't screw up our state
404 filename = os.path.expandvars(filename) 409 filename = os.path.expandvars(filename)
405 line_feeder = _FileFeed(filename) 410 line_feeder = _FileFeed(filename)
406 411
407 self.config_filename = filename 412 self.config_filename = filename
408 413
409 # 414 #
410 # Read header 415 # Read header
411 # 416 #
412 417
413 def is_header_line(line): 418 def is_header_line(line):
414 return line is not None and line.startswith("#") and \ 419 return line is not None and line.startswith("#") and \
415 not _unset_re_match(line) 420 not _unset_re_match(line)
416 421
417 self.config_header = None 422 self.config_header = None
418 423
419 line = line_feeder.peek_next() 424 line = line_feeder.peek_next()
420 if is_header_line(line): 425 if is_header_line(line):
421 self.config_header = "" 426 self.config_header = ""
422 while is_header_line(line_feeder.peek_next()): 427 while is_header_line(line_feeder.peek_next()):
423 self.config_header += line_feeder.get_next()[1:] 428 self.config_header += line_feeder.get_next()[1:]
424 # Remove trailing newline 429 # Remove trailing newline
425 if self.config_header.endswith("\n"): 430 if self.config_header.endswith("\n"):
426 self.config_header = self.config_header[:-1] 431 self.config_header = self.config_header[:-1]
427 432
428 # 433 #
429 # Read assignments. Hotspot for some workloads. 434 # Read assignments. Hotspot for some workloads.
430 # 435 #
431 436
432 def warn_override(filename, linenr, name, old_user_val, new_user_val): 437 def warn_override(filename, linenr, name, old_user_val, new_user_val):
433 self._warn('overriding the value of {0}. ' 438 self._warn('overriding the value of {0}. '
434 'Old value: "{1}", new value: "{2}".' 439 'Old value: "{1}", new value: "{2}".'
435 .format(name, old_user_val, new_user_val), 440 .format(name, old_user_val, new_user_val),
436 filename, linenr) 441 filename, linenr)
437 442
438 # Invalidate everything to keep things simple. It might be possible to 443 # Invalidate everything to keep things simple. It might be possible to
439 # improve performance for the case where multiple configurations are 444 # improve performance for the case where multiple configurations are
440 # loaded by only invalidating a symbol (and its dependent symbols) if 445 # loaded by only invalidating a symbol (and its dependent symbols) if
441 # the new user value differs from the old. One complication would be 446 # the new user value differs from the old. One complication would be
442 # that symbols not mentioned in the .config must lose their user value 447 # that symbols not mentioned in the .config must lose their user value
443 # when replace = True, which is the usual case. 448 # when replace = True, which is the usual case.
444 if replace: 449 if replace:
445 self.unset_user_values() 450 self.unset_user_values()
446 else: 451 else:
447 self._invalidate_all() 452 self._invalidate_all()
448 453
449 while 1: 454 while 1:
450 line = line_feeder.get_next() 455 line = line_feeder.get_next()
451 if line is None: 456 if line is None:
452 return 457 return self._warnings
453 458
454 line = line.rstrip() 459 line = line.rstrip()
455 460
456 set_match = _set_re_match(line) 461 set_match = _set_re_match(line)
457 if set_match: 462 if set_match:
458 name, val = set_match.groups() 463 name, val = set_match.groups()
459 464
460 if val.startswith('"'): 465 if val.startswith('"'):
461 if len(val) < 2 or val[-1] != '"': 466 if len(val) < 2 or val[-1] != '"':
462 _parse_error(line, "malformed string literal", 467 _parse_error(line, "malformed string literal",
463 line_feeder.filename, line_feeder.linenr) 468 line_feeder.filename, line_feeder.linenr)
464 # Strip quotes and remove escapings. The unescaping 469 # Strip quotes and remove escapings. The unescaping
465 # procedure should be safe since " can only appear as \" 470 # procedure should be safe since " can only appear as \"
466 # inside the string. 471 # inside the string.
467 val = val[1:-1].replace('\\"', '"').replace("\\\\", "\\") 472 val = val[1:-1].replace('\\"', '"').replace("\\\\", "\\")
468 473
469 if name in self.syms: 474 if name in self.syms:
470 sym = self.syms[name] 475 sym = self.syms[name]
471 if sym.user_val is not None: 476 if sym.user_val is not None:
472 warn_override(line_feeder.filename, line_feeder.linenr, 477 warn_override(line_feeder.filename, line_feeder.linenr,
473 name, sym.user_val, val) 478 name, sym.user_val, val)
474 479
475 if sym.is_choice_sym: 480 if sym.is_choice_sym:
476 user_mode = sym.parent.user_mode 481 user_mode = sym.parent.user_mode
477 if user_mode is not None and user_mode != val: 482 if user_mode is not None and user_mode != val:
478 self._warn("assignment to {0} changes mode of " 483 self._warn("assignment to {0} changes mode of "
479 'containing choice from "{1}" to "{2}".' 484 'containing choice from "{1}" to "{2}".'
480 .format(name, val, user_mode), 485 .format(name, val, user_mode),
481 line_feeder.filename, 486 line_feeder.filename,
482 line_feeder.linenr) 487 line_feeder.linenr)
483 488
484 sym._set_user_value_no_invalidate(val, True) 489 sym._set_user_value_no_invalidate(val, True)
485 else: 490 else:
486 if self.print_undef_assign: 491 if self.print_undef_assign:
487 _stderr_msg('note: attempt to assign the value "{0}" ' 492 _stderr_msg('note: attempt to assign the value "{0}" '
488 "to the undefined symbol {1}." 493 "to the undefined symbol {1}."
489 .format(val, name), 494 .format(val, name),
490 line_feeder.filename, line_feeder.linenr) 495 line_feeder.filename, line_feeder.linenr)
491 else: 496 else:
492 unset_match = _unset_re_match(line) 497 unset_match = _unset_re_match(line)
493 if unset_match: 498 if unset_match:
494 name = unset_match.group(1) 499 name = unset_match.group(1)
495 if name in self.syms: 500 if name in self.syms:
496 sym = self.syms[name] 501 sym = self.syms[name]
497 if sym.user_val is not None: 502 if sym.user_val is not None:
498 warn_override(line_feeder.filename, 503 warn_override(line_feeder.filename,
499 line_feeder.linenr, 504 line_feeder.linenr,
500 name, sym.user_val, "n") 505 name, sym.user_val, "n")
501 506
502 sym._set_user_value_no_invalidate("n", True) 507 sym._set_user_value_no_invalidate("n", True)
503 508
504 def write_config(self, filename, header=None): 509 def write_config(self, filename, header=None):
505 """Writes out symbol values in the familiar .config format. 510 """Writes out symbol values in the familiar .config format.
506 511
507 Kconfiglib makes sure the format matches what the C implementation 512 Kconfiglib makes sure the format matches what the C implementation
508 would generate, down to whitespace. This eases testing. 513 would generate, down to whitespace. This eases testing.
509 514
510 filename: The filename under which to save the configuration. 515 filename: The filename under which to save the configuration.
511 516
512 header (default: None): A textual header that will appear at the 517 header (default: None): A textual header that will appear at the
513 beginning of the file, with each line commented out automatically. 518 beginning of the file, with each line commented out automatically.
514 None means no header.""" 519 None means no header."""
515 520
516 for sym in self.syms_iter(): 521 for sym in self.syms_iter():
517 sym.already_written = False 522 sym.already_written = False
518 523
519 with open(filename, "w") as f: 524 with open(filename, "w") as f:
520 # Write header 525 # Write header
521 if header is not None: 526 if header is not None:
522 f.write(_comment(header)) 527 f.write(_comment(header))
523 f.write("\n") 528 f.write("\n")
524 529
525 # Build and write configuration 530 # Build and write configuration
526 conf_strings = [] 531 conf_strings = []
527 _make_block_conf(self.top_block, conf_strings.append) 532 _make_block_conf(self.top_block, conf_strings.append)
528 f.write("\n".join(conf_strings)) 533 f.write("\n".join(conf_strings))
529 f.write("\n") 534 f.write("\n")
530 535
531 def eval(self, s): 536 def eval(self, s):
532 """Returns the value of the expression 's' -- where 's' is represented 537 """Returns the value of the expression 's' -- where 's' is represented
533 as a string -- in the context of the configuration. Raises 538 as a string -- in the context of the configuration. Raises
534 Kconfig_Syntax_Error if syntax errors are detected in 's'. 539 Kconfig_Syntax_Error if syntax errors are detected in 's'.
535 540
536 For example, if FOO and BAR are tristate symbols at least one of which 541 For example, if FOO and BAR are tristate symbols at least one of which
537 has the value "y", then config.eval("y && (FOO || BAR)") => "y" 542 has the value "y", then config.eval("y && (FOO || BAR)") => "y"
538 543
539 This function always yields a tristate value. To get the value of 544 This function always yields a tristate value. To get the value of
540 non-bool, non-tristate symbols, use Symbol.get_value(). 545 non-bool, non-tristate symbols, use Symbol.get_value().
541 546
542 The result of this function is consistent with how evaluation works for 547 The result of this function is consistent with how evaluation works for
543 conditional expressions in the configuration as well as in the C 548 conditional expressions in the configuration as well as in the C
544 implementation. "m" and m are rewritten as '"m" && MODULES' and 'm && 549 implementation. "m" and m are rewritten as '"m" && MODULES' and 'm &&
545 MODULES', respectively, and a result of "m" will get promoted to "y" if 550 MODULES', respectively, and a result of "m" will get promoted to "y" if
546 we're running without modules. 551 we're running without modules.
547 552
548 Syntax checking is somewhat lax, partly to be compatible with lax 553 Syntax checking is somewhat lax, partly to be compatible with lax
549 parsing in the C implementation.""" 554 parsing in the C implementation."""
550 return self._eval_expr(self._parse_expr(self._tokenize(s, True), # Feed 555 return self._eval_expr(self._parse_expr(self._tokenize(s, True), # Feed
551 None, # Current symbol/choice 556 None, # Current symbol/choice
552 s)) # line 557 s)) # line
553 558
554 def unset_user_values(self): 559 def unset_user_values(self):
555 """Resets the values of all symbols, as if Config.load_config() or 560 """Resets the values of all symbols, as if Config.load_config() or
556 Symbol.set_user_value() had never been called.""" 561 Symbol.set_user_value() had never been called."""
557 for sym in self.syms_iter(): 562 for sym in self.syms_iter():
558 sym._unset_user_value_no_recursive_invalidate() 563 sym._unset_user_value_no_recursive_invalidate()
559 564
560 def set_print_warnings(self, print_warnings): 565 def set_print_warnings(self, print_warnings):
561 """Determines whether warnings related to this configuration (for 566 """Determines whether warnings related to this configuration (for
562 things like attempting to assign illegal values to symbols with 567 things like attempting to assign illegal values to symbols with
563 Symbol.set_user_value()) should be printed to stderr. 568 Symbol.set_user_value()) should be printed to stderr.
564 569
565 print_warnings: True if warnings should be printed.""" 570 print_warnings: True if warnings should be printed."""
566 self.print_warnings = print_warnings 571 self.print_warnings = print_warnings
567 572
568 def set_print_undef_assign(self, print_undef_assign): 573 def set_print_undef_assign(self, print_undef_assign):
569 """Determines whether informational messages related to assignments to 574 """Determines whether informational messages related to assignments to
570 undefined symbols should be printed to stderr for this configuration. 575 undefined symbols should be printed to stderr for this configuration.
571 576
572 print_undef_assign: If True, such messages will be printed.""" 577 print_undef_assign: If True, such messages will be printed."""
573 self.print_undef_assign = print_undef_assign 578 self.print_undef_assign = print_undef_assign
574 579
575 def __str__(self): 580 def __str__(self):
576 """Returns a string containing various information about the Config.""" 581 """Returns a string containing various information about the Config."""
577 return _lines("Configuration", 582 return _lines("Configuration",
578 "File : " + 583 "File : " +
579 self.filename, 584 self.filename,
580 "Base directory : " + 585 "Base directory : " +
581 self.base_dir, 586 self.base_dir,
582 "Value of $ARCH at creation time : " + 587 "Value of $ARCH at creation time : " +
583 ("(not set)" if self.arch is None else self.arch), 588 ("(not set)" if self.arch is None else self.arch),
584 "Value of $SRCARCH at creation time : " + 589 "Value of $SRCARCH at creation time : " +
585 ("(not set)" if self.srcarch is None else 590 ("(not set)" if self.srcarch is None else
586 self.srcarch), 591 self.srcarch),
587 "Source tree (derived from $srctree;", 592 "Source tree (derived from $srctree;",
588 "defaults to '.' if $srctree isn't set) : " + 593 "defaults to '.' if $srctree isn't set) : " +
589 self.srctree, 594 self.srctree,
590 "Most recently loaded .config : " + 595 "Most recently loaded .config : " +
591 ("(no .config loaded)" 596 ("(no .config loaded)"
592 if self.config_filename is None else 597 if self.config_filename is None else
593 self.config_filename), 598 self.config_filename),
594 "Print warnings : " + 599 "Print warnings : " +
595 BOOL_STR[self.print_warnings], 600 BOOL_STR[self.print_warnings],
596 "Print assignments to undefined symbols : " + 601 "Print assignments to undefined symbols : " +
597 BOOL_STR[self.print_undef_assign]) 602 BOOL_STR[self.print_undef_assign])
598 603
599 # 604 #
600 # Private methods 605 # Private methods
601 # 606 #
602 607
603 # 608 #
604 # Kconfig parsing 609 # Kconfig parsing
605 # 610 #
606 611
607 def _parse_file(self, filename, parent, deps, visible_if_deps, res=None): 612 def _parse_file(self, filename, parent, deps, visible_if_deps, res=None):
608 """Parses the Kconfig file 'filename'. Returns a list with the Items in 613 """Parses the Kconfig file 'filename'. Returns a list with the Items in
609 the file. See _parse_block() for the meaning of the parameters.""" 614 the file. See _parse_block() for the meaning of the parameters."""
610 return self._parse_block(_FileFeed(filename), None, parent, deps, 615 return self._parse_block(_FileFeed(filename), None, parent, deps,
611 visible_if_deps, res) 616 visible_if_deps, res)
612 617
613 def _parse_block(self, line_feeder, end_marker, parent, deps, 618 def _parse_block(self, line_feeder, end_marker, parent, deps,
614 visible_if_deps, res=None): 619 visible_if_deps, res=None):
615 """Parses a block, which is the contents of either a file or an if, 620 """Parses a block, which is the contents of either a file or an if,
616 menu, or choice statement. Returns a list with the Items in the block. 621 menu, or choice statement. Returns a list with the Items in the block.
617 622
618 line_feeder: A _FileFeed instance feeding lines from a file. The 623 line_feeder: A _FileFeed instance feeding lines from a file. The
619 Kconfig language is line-based in practice. 624 Kconfig language is line-based in practice.
620 625
621 end_marker: The token that ends the block, e.g. T_ENDIF ("endif") for 626 end_marker: The token that ends the block, e.g. T_ENDIF ("endif") for
622 ifs. None for files. 627 ifs. None for files.
623 628
624 parent: The enclosing menu or choice, or None if we're at the top 629 parent: The enclosing menu or choice, or None if we're at the top
625 level. 630 level.
626 631
627 deps: Dependencies from enclosing menus, choices and ifs. 632 deps: Dependencies from enclosing menus, choices and ifs.
628 633
629 visible_if_deps (default: None): 'visible if' dependencies from 634 visible_if_deps (default: None): 'visible if' dependencies from
630 enclosing menus. 635 enclosing menus.
631 636
632 res (default: None): The list to add items to. If None, a new list is 637 res (default: None): The list to add items to. If None, a new list is
633 created to hold the items.""" 638 created to hold the items."""
634 639
635 block = [] if res is None else res 640 block = [] if res is None else res
636 641
637 while 1: 642 while 1:
638 # Do we already have a tokenized line that we determined wasn't 643 # Do we already have a tokenized line that we determined wasn't
639 # part of whatever we were parsing earlier? See comment in 644 # part of whatever we were parsing earlier? See comment in
640 # Config.__init__(). 645 # Config.__init__().
641 if self.end_line is not None: 646 if self.end_line is not None:
642 line = self.end_line 647 line = self.end_line
643 tokens = self.end_line_tokens 648 tokens = self.end_line_tokens
644 tokens.unget_all() 649 tokens.unget_all()
645 650
646 self.end_line = None 651 self.end_line = None
647 self.end_line_tokens = None 652 self.end_line_tokens = None
648 else: 653 else:
649 line = line_feeder.get_next() 654 line = line_feeder.get_next()
650 if line is None: 655 if line is None:
651 if end_marker is not None: 656 if end_marker is not None:
652 raise Kconfig_Syntax_Error("Unexpected end of file {0}" 657 raise Kconfig_Syntax_Error("Unexpected end of file {0}"
653 .format(line_feeder.filename)) 658 .format(line_feeder.filename))
654 return block 659 return block
655 660
656 tokens = self._tokenize(line, False, line_feeder.filename, 661 tokens = self._tokenize(line, False, line_feeder.filename,
657 line_feeder.linenr) 662 line_feeder.linenr)
658 663
659 t0 = tokens.get_next() 664 t0 = tokens.get_next()
660 if t0 is None: 665 if t0 is None:
661 continue 666 continue
662 667
663 # Cases are ordered roughly by frequency, which speeds things up a 668 # Cases are ordered roughly by frequency, which speeds things up a
664 # bit 669 # bit
665 670
666 if t0 == T_CONFIG or t0 == T_MENUCONFIG: 671 if t0 == T_CONFIG or t0 == T_MENUCONFIG:
667 # The tokenizer will automatically allocate a new Symbol object 672 # The tokenizer will automatically allocate a new Symbol object
668 # for any new names it encounters, so we don't need to worry 673 # for any new names it encounters, so we don't need to worry
669 # about that here. 674 # about that here.
670 sym = tokens.get_next() 675 sym = tokens.get_next()
671 676
672 # Symbols defined in multiple places get the parent of their 677 # Symbols defined in multiple places get the parent of their
673 # first definition. However, for symbols whose parents are 678 # first definition. However, for symbols whose parents are
674 # choice statements, the choice statement takes precedence. 679 # choice statements, the choice statement takes precedence.
675 if not sym.is_defined_ or isinstance(parent, Choice): 680 if not sym.is_defined_ or isinstance(parent, Choice):
676 sym.parent = parent 681 sym.parent = parent
677 682
678 sym.is_defined_ = True 683 sym.is_defined_ = True
679 684
680 self.kconfig_syms.append(sym) 685 self.kconfig_syms.append(sym)
681 block.append(sym) 686 block.append(sym)
682 687
683 self._parse_properties(line_feeder, sym, deps, visible_if_deps) 688 self._parse_properties(line_feeder, sym, deps, visible_if_deps)
684 689
685 elif t0 == T_SOURCE: 690 elif t0 == T_SOURCE:
686 kconfig_file = tokens.get_next() 691 kconfig_file = tokens.get_next()
687 exp_kconfig_file = self._expand_sym_refs(kconfig_file) 692 exp_kconfig_file = self._expand_sym_refs(kconfig_file)
688 f = os.path.join(self.base_dir, exp_kconfig_file) 693 f = os.path.join(self.base_dir, exp_kconfig_file)
689 if not os.path.exists(f): 694 if not os.path.exists(f):
690 raise IOError('{0}:{1}: sourced file "{2}" (expands to ' 695 raise IOError('{0}:{1}: sourced file "{2}" (expands to '
691 '"{3}") not found. Perhaps base_dir ' 696 '"{3}") not found. Perhaps base_dir '
692 '(argument to Config.__init__(), currently ' 697 '(argument to Config.__init__(), currently '
693 '"{4}") is set to the wrong value.' 698 '"{4}") is set to the wrong value.'
694 .format(line_feeder.filename, 699 .format(line_feeder.filename,
695 line_feeder.linenr, 700 line_feeder.linenr,
696 kconfig_file, exp_kconfig_file, 701 kconfig_file, exp_kconfig_file,
697 self.base_dir)) 702 self.base_dir))
698 # Add items to the same block 703 # Add items to the same block
699 self._parse_file(f, parent, deps, visible_if_deps, block) 704 self._parse_file(f, parent, deps, visible_if_deps, block)
700 705
701 elif t0 == end_marker: 706 elif t0 == end_marker:
702 # We have reached the end of the block 707 # We have reached the end of the block
703 return block 708 return block
704 709
705 elif t0 == T_IF: 710 elif t0 == T_IF:
706 # If statements are treated as syntactic sugar for adding 711 # If statements are treated as syntactic sugar for adding
707 # dependencies to enclosed items and do not have an explicit 712 # dependencies to enclosed items and do not have an explicit
708 # object representation. 713 # object representation.
709 714
710 dep_expr = self._parse_expr(tokens, None, line, 715 dep_expr = self._parse_expr(tokens, None, line,
711 line_feeder.filename, 716 line_feeder.filename,
712 line_feeder.linenr) 717 line_feeder.linenr)
713 # Add items to the same block 718 # Add items to the same block
714 self._parse_block(line_feeder, T_ENDIF, parent, 719 self._parse_block(line_feeder, T_ENDIF, parent,
715 _make_and(dep_expr, deps), 720 _make_and(dep_expr, deps),
716 visible_if_deps, block) 721 visible_if_deps, block)
717 722
718 elif t0 == T_COMMENT: 723 elif t0 == T_COMMENT:
719 comment = Comment() 724 comment = Comment()
720 725
721 comment.config = self 726 comment.config = self
722 comment.parent = parent 727 comment.parent = parent
723 comment.filename = line_feeder.filename 728 comment.filename = line_feeder.filename
724 comment.linenr = line_feeder.linenr 729 comment.linenr = line_feeder.linenr
725 comment.text = tokens.get_next() 730 comment.text = tokens.get_next()
726 731
727 self.comments.append(comment) 732 self.comments.append(comment)
728 block.append(comment) 733 block.append(comment)
729 734
730 self._parse_properties(line_feeder, comment, deps, 735 self._parse_properties(line_feeder, comment, deps,
731 visible_if_deps) 736 visible_if_deps)
732 737
733 elif t0 == T_MENU: 738 elif t0 == T_MENU:
734 menu = Menu() 739 menu = Menu()
735 740
736 menu.config = self 741 menu.config = self
737 menu.parent = parent 742 menu.parent = parent
738 menu.filename = line_feeder.filename 743 menu.filename = line_feeder.filename
739 menu.linenr = line_feeder.linenr 744 menu.linenr = line_feeder.linenr
740 menu.title = tokens.get_next() 745 menu.title = tokens.get_next()
741 746
742 self.menus.append(menu) 747 self.menus.append(menu)
743 block.append(menu) 748 block.append(menu)
744 749
745 # Parse properties and contents 750 # Parse properties and contents
746 self._parse_properties(line_feeder, menu, deps, 751 self._parse_properties(line_feeder, menu, deps,
747 visible_if_deps) 752 visible_if_deps)
748 menu.block = self._parse_block(line_feeder, T_ENDMENU, menu, 753 menu.block = self._parse_block(line_feeder, T_ENDMENU, menu,
749 menu.dep_expr, 754 menu.dep_expr,
750 _make_and(visible_if_deps, 755 _make_and(visible_if_deps,
751 menu.visible_if_expr)) 756 menu.visible_if_expr))
752 757
753 elif t0 == T_CHOICE: 758 elif t0 == T_CHOICE:
754 name = tokens.get_next() 759 name = tokens.get_next()
755 if name is None: 760 if name is None:
756 choice = Choice() 761 choice = Choice()
757 self.choices.append(choice) 762 self.choices.append(choice)
758 else: 763 else:
759 # Named choice 764 # Named choice
760 choice = self.named_choices.get(name) 765 choice = self.named_choices.get(name)
761 if choice is None: 766 if choice is None:
762 choice = Choice() 767 choice = Choice()
763 choice.name = name 768 choice.name = name
764 self.named_choices[name] = choice 769 self.named_choices[name] = choice
765 self.choices.append(choice) 770 self.choices.append(choice)
766 771
767 choice.config = self 772 choice.config = self
768 choice.parent = parent 773 choice.parent = parent
769 774
770 choice.def_locations.append((line_feeder.filename, 775 choice.def_locations.append((line_feeder.filename,
771 line_feeder.linenr)) 776 line_feeder.linenr))
772 777
773 # Parse properties and contents 778 # Parse properties and contents
774 self._parse_properties(line_feeder, choice, deps, 779 self._parse_properties(line_feeder, choice, deps,
775 visible_if_deps) 780 visible_if_deps)
776 choice.block = self._parse_block(line_feeder, T_ENDCHOICE, 781 choice.block = self._parse_block(line_feeder, T_ENDCHOICE,
777 choice, deps, visible_if_deps) 782 choice, deps, visible_if_deps)
778 783
779 choice._determine_actual_symbols() 784 choice._determine_actual_symbols()
780 785
781 # If no type is specified for the choice, its type is that of 786 # If no type is specified for the choice, its type is that of
782 # the first choice item with a specified type 787 # the first choice item with a specified type
783 if choice.type == UNKNOWN: 788 if choice.type == UNKNOWN:
784 for item in choice.actual_symbols: 789 for item in choice.actual_symbols:
785 if item.type != UNKNOWN: 790 if item.type != UNKNOWN:
786 choice.type = item.type 791 choice.type = item.type
787 break 792 break
788 793
789 # Each choice item of UNKNOWN type gets the type of the choice 794 # Each choice item of UNKNOWN type gets the type of the choice
790 for item in choice.actual_symbols: 795 for item in choice.actual_symbols:
791 if item.type == UNKNOWN: 796 if item.type == UNKNOWN:
792 item.type = choice.type 797 item.type = choice.type
793 798
794 block.append(choice) 799 block.append(choice)
795 800
796 elif t0 == T_MAINMENU: 801 elif t0 == T_MAINMENU:
797 text = tokens.get_next() 802 text = tokens.get_next()
798 if self.mainmenu_text is not None: 803 if self.mainmenu_text is not None:
799 self._warn("overriding 'mainmenu' text. " 804 self._warn("overriding 'mainmenu' text. "
800 'Old value: "{0}", new value: "{1}".' 805 'Old value: "{0}", new value: "{1}".'
801 .format(self.mainmenu_text, text), 806 .format(self.mainmenu_text, text),
802 line_feeder.filename, line_feeder.linenr) 807 line_feeder.filename, line_feeder.linenr)
803 self.mainmenu_text = text 808 self.mainmenu_text = text
804 809
805 else: 810 else:
806 _parse_error(line, "unrecognized construct", 811 _parse_error(line, "unrecognized construct",
807 line_feeder.filename, line_feeder.linenr) 812 line_feeder.filename, line_feeder.linenr)
808 813
809 def _parse_properties(self, line_feeder, stmt, deps, visible_if_deps): 814 def _parse_properties(self, line_feeder, stmt, deps, visible_if_deps):
810 """Parsing of properties for symbols, menus, choices, and comments. 815 """Parsing of properties for symbols, menus, choices, and comments.
811 Takes care of propagating dependencies from enclosing menus and ifs.""" 816 Takes care of propagating dependencies from enclosing menus and ifs."""
812 817
813 def parse_val_and_cond(tokens, line, filename, linenr): 818 def parse_val_and_cond(tokens, line, filename, linenr):
814 """Parses '<expr1> if <expr2>' constructs, where the 'if' part is 819 """Parses '<expr1> if <expr2>' constructs, where the 'if' part is
815 optional. Returns a tuple containing the parsed expressions, with 820 optional. Returns a tuple containing the parsed expressions, with
816 None as the second element if the 'if' part is missing.""" 821 None as the second element if the 'if' part is missing."""
817 val = self._parse_expr(tokens, stmt, line, filename, linenr, False) 822 val = self._parse_expr(tokens, stmt, line, filename, linenr, False)
818 if tokens.check(T_IF): 823 if tokens.check(T_IF):
819 return (val, self._parse_expr(tokens, stmt, line, filename, 824 return (val, self._parse_expr(tokens, stmt, line, filename,
820 linenr)) 825 linenr))
821 return (val, None) 826 return (val, None)
822 827
823 # In case the symbol is defined in multiple locations, we need to 828 # In case the symbol is defined in multiple locations, we need to
824 # remember what prompts, defaults, and selects are new for this 829 # remember what prompts, defaults, and selects are new for this
825 # definition, as "depends on" should only apply to the local 830 # definition, as "depends on" should only apply to the local
826 # definition. 831 # definition.
827 new_prompt = None 832 new_prompt = None
828 new_def_exprs = [] 833 new_def_exprs = []
829 new_selects = [] 834 new_selects = []
830 835
831 # Dependencies from 'depends on' statements 836 # Dependencies from 'depends on' statements
832 depends_on_expr = None 837 depends_on_expr = None
833 838
834 while 1: 839 while 1:
835 line = line_feeder.get_next() 840 line = line_feeder.get_next()
836 if line is None: 841 if line is None:
837 break 842 break
838 843
839 filename = line_feeder.filename 844 filename = line_feeder.filename
840 linenr = line_feeder.linenr 845 linenr = line_feeder.linenr
841 846
842 tokens = self._tokenize(line, False, filename, linenr) 847 tokens = self._tokenize(line, False, filename, linenr)
843 848
844 t0 = tokens.get_next() 849 t0 = tokens.get_next()
845 if t0 is None: 850 if t0 is None:
846 continue 851 continue
847 852
848 # Cases are ordered roughly by frequency, which speeds things up a 853 # Cases are ordered roughly by frequency, which speeds things up a
849 # bit 854 # bit
850 855
851 if t0 == T_DEPENDS: 856 if t0 == T_DEPENDS:
852 if not tokens.check(T_ON): 857 if not tokens.check(T_ON):
853 _parse_error(line, 'expected "on" after "depends"', 858 _parse_error(line, 'expected "on" after "depends"',
854 filename, linenr) 859 filename, linenr)
855 860
856 parsed_deps = self._parse_expr(tokens, stmt, line, filename, 861 parsed_deps = self._parse_expr(tokens, stmt, line, filename,
857 linenr) 862 linenr)
858 863
859 if isinstance(stmt, (Menu, Comment)): 864 if isinstance(stmt, (Menu, Comment)):
860 stmt.orig_deps = _make_and(stmt.orig_deps, parsed_deps) 865 stmt.orig_deps = _make_and(stmt.orig_deps, parsed_deps)
861 else: 866 else:
862 depends_on_expr = _make_and(depends_on_expr, parsed_deps) 867 depends_on_expr = _make_and(depends_on_expr, parsed_deps)
863 868
864 elif t0 == T_HELP: 869 elif t0 == T_HELP:
865 # Find first non-blank (not all-space) line and get its 870 # Find first non-blank (not all-space) line and get its
866 # indentation 871 # indentation
867 line = line_feeder.next_nonblank() 872 line = line_feeder.next_nonblank()
868 if line is None: 873 if line is None:
869 stmt.help = "" 874 stmt.help = ""
870 break 875 break
871 indent = _indentation(line) 876 indent = _indentation(line)
872 if indent == 0: 877 if indent == 0:
873 # If the first non-empty lines has zero indent, there is no 878 # If the first non-empty lines has zero indent, there is no
874 # help text 879 # help text
875 stmt.help = "" 880 stmt.help = ""
876 line_feeder.unget() 881 line_feeder.unget()
877 break 882 break
878 883
879 # The help text goes on till the first non-empty line with less 884 # The help text goes on till the first non-empty line with less
880 # indent 885 # indent
881 help_lines = [_deindent(line, indent)] 886 help_lines = [_deindent(line, indent)]
882 while 1: 887 while 1:
883 line = line_feeder.get_next() 888 line = line_feeder.get_next()
884 if line is None or \ 889 if line is None or \
885 (not line.isspace() and _indentation(line) < indent): 890 (not line.isspace() and _indentation(line) < indent):
886 stmt.help = "".join(help_lines) 891 stmt.help = "".join(help_lines)
887 break 892 break
888 help_lines.append(_deindent(line, indent)) 893 help_lines.append(_deindent(line, indent))
889 894
890 if line is None: 895 if line is None:
891 break 896 break
892 897
893 line_feeder.unget() 898 line_feeder.unget()
894 899
895 elif t0 == T_SELECT or t0 == T_IMPLY: 900 elif t0 == T_SELECT or t0 == T_IMPLY:
896 target = tokens.get_next() 901 target = tokens.get_next()
897 902
898 stmt.referenced_syms.add(target) 903 stmt.referenced_syms.add(target)
899 stmt.selected_syms.add(target) 904 stmt.selected_syms.add(target)
900 905
901 if tokens.check(T_IF): 906 if tokens.check(T_IF):
902 new_selects.append((target, 907 new_selects.append((target,
903 self._parse_expr(tokens, stmt, line, 908 self._parse_expr(tokens, stmt, line,
904 filename, linenr))) 909 filename, linenr)))
905 else: 910 else:
906 new_selects.append((target, None)) 911 new_selects.append((target, None))
907 912
908 elif t0 in (T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING): 913 elif t0 in (T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING):
909 stmt.type = TOKEN_TO_TYPE[t0] 914 stmt.type = TOKEN_TO_TYPE[t0]
910 if tokens.peek_next() is not None: 915 if tokens.peek_next() is not None:
911 new_prompt = parse_val_and_cond(tokens, line, filename, 916 new_prompt = parse_val_and_cond(tokens, line, filename,
912 linenr) 917 linenr)
913 918
914 elif t0 == T_DEFAULT: 919 elif t0 == T_DEFAULT:
915 new_def_exprs.append(parse_val_and_cond(tokens, line, filename, 920 new_def_exprs.append(parse_val_and_cond(tokens, line, filename,
916 linenr)) 921 linenr))
917 922
918 elif t0 == T_DEF_BOOL: 923 elif t0 == T_DEF_BOOL:
919 stmt.type = BOOL 924 stmt.type = BOOL
920 if tokens.peek_next() is not None: 925 if tokens.peek_next() is not None:
921 new_def_exprs.append(parse_val_and_cond(tokens, line, 926 new_def_exprs.append(parse_val_and_cond(tokens, line,
922 filename, linenr)) 927 filename, linenr))
923 928
924 elif t0 == T_PROMPT: 929 elif t0 == T_PROMPT:
925 # 'prompt' properties override each other within a single 930 # 'prompt' properties override each other within a single
926 # definition of a symbol, but additional prompts can be added 931 # definition of a symbol, but additional prompts can be added
927 # by defining the symbol multiple times; hence 'new_prompt' 932 # by defining the symbol multiple times; hence 'new_prompt'
928 # instead of 'prompt'. 933 # instead of 'prompt'.
929 new_prompt = parse_val_and_cond(tokens, line, filename, linenr) 934 new_prompt = parse_val_and_cond(tokens, line, filename, linenr)
930 935
931 elif t0 == T_RANGE: 936 elif t0 == T_RANGE:
932 low = tokens.get_next() 937 low = tokens.get_next()
933 high = tokens.get_next() 938 high = tokens.get_next()
934 stmt.referenced_syms.add(low) 939 stmt.referenced_syms.add(low)
935 stmt.referenced_syms.add(high) 940 stmt.referenced_syms.add(high)
936 941
937 if tokens.check(T_IF): 942 if tokens.check(T_IF):
938 stmt.ranges.append((low, high, 943 stmt.ranges.append((low, high,
939 self._parse_expr(tokens, stmt, line, 944 self._parse_expr(tokens, stmt, line,
940 filename, linenr))) 945 filename, linenr)))
941 else: 946 else:
942 stmt.ranges.append((low, high, None)) 947 stmt.ranges.append((low, high, None))
943 948
944 elif t0 == T_DEF_TRISTATE: 949 elif t0 == T_DEF_TRISTATE:
945 stmt.type = TRISTATE 950 stmt.type = TRISTATE
946 if tokens.peek_next() is not None: 951 if tokens.peek_next() is not None:
947 new_def_exprs.append(parse_val_and_cond(tokens, line, 952 new_def_exprs.append(parse_val_and_cond(tokens, line,
948 filename, linenr)) 953 filename, linenr))
949 954
950 elif t0 == T_OPTION: 955 elif t0 == T_OPTION:
951 if tokens.check(T_ENV) and tokens.check(T_EQUAL): 956 if tokens.check(T_ENV) and tokens.check(T_EQUAL):
952 env_var = tokens.get_next() 957 env_var = tokens.get_next()
953 958
954 stmt.is_special_ = True 959 stmt.is_special_ = True
955 stmt.is_from_env = True 960 stmt.is_from_env = True
956 961
957 if env_var not in os.environ: 962 if env_var not in os.environ:
958 self._warn("The symbol {0} references the " 963 self._warn("The symbol {0} references the "
959 "non-existent environment variable {1} and " 964 "non-existent environment variable {1} and "
960 "will get the empty string as its value. " 965 "will get the empty string as its value. "
961 "If you're using Kconfiglib via " 966 "If you're using Kconfiglib via "
962 "'make (i)scriptconfig', it should have " 967 "'make (i)scriptconfig', it should have "
963 "set up the environment correctly for you. " 968 "set up the environment correctly for you. "
964 "If you still got this message, that " 969 "If you still got this message, that "
965 "might be an error, and you should email " 970 "might be an error, and you should email "
966 "ulfalizer a.t Google's email service.""" 971 "ulfalizer a.t Google's email service."""
967 .format(stmt.name, env_var), 972 .format(stmt.name, env_var),
968 filename, linenr) 973 filename, linenr)
969 974
970 stmt.cached_val = "" 975 stmt.cached_val = ""
971 else: 976 else:
972 stmt.cached_val = os.environ[env_var] 977 stmt.cached_val = os.environ[env_var]
973 978
974 elif tokens.check(T_DEFCONFIG_LIST): 979 elif tokens.check(T_DEFCONFIG_LIST):
975 self.defconfig_sym = stmt 980 self.defconfig_sym = stmt
976 981
977 elif tokens.check(T_MODULES): 982 elif tokens.check(T_MODULES):
978 # To reduce warning spam, only warn if 'option modules' is 983 # To reduce warning spam, only warn if 'option modules' is
979 # set on some symbol that isn't MODULES, which should be 984 # set on some symbol that isn't MODULES, which should be
980 # safe. I haven't run into any projects that make use 985 # safe. I haven't run into any projects that make use
981 # modules besides the kernel yet, and there it's likely to 986 # modules besides the kernel yet, and there it's likely to
982 # keep being called "MODULES". 987 # keep being called "MODULES".
983 if stmt.name != "MODULES": 988 if stmt.name != "MODULES":
984 self._warn("the 'modules' option is not supported. " 989 self._warn("the 'modules' option is not supported. "
985 "Let me know if this is a problem for you; " 990 "Let me know if this is a problem for you; "
986 "it shouldn't be that hard to implement. " 991 "it shouldn't be that hard to implement. "
987 "(Note that modules are still supported -- " 992 "(Note that modules are still supported -- "
988 "Kconfiglib just assumes the symbol name " 993 "Kconfiglib just assumes the symbol name "
989 "MODULES, like older versions of the C " 994 "MODULES, like older versions of the C "
990 "implementation did when 'option modules' " 995 "implementation did when 'option modules' "
991 "wasn't used.)", 996 "wasn't used.)",
992 filename, linenr) 997 filename, linenr)
993 998
994 elif tokens.check(T_ALLNOCONFIG_Y): 999 elif tokens.check(T_ALLNOCONFIG_Y):
995 if not isinstance(stmt, Symbol): 1000 if not isinstance(stmt, Symbol):
996 _parse_error(line, 1001 _parse_error(line,
997 "the 'allnoconfig_y' option is only " 1002 "the 'allnoconfig_y' option is only "
998 "valid for symbols", 1003 "valid for symbols",
999 filename, linenr) 1004 filename, linenr)
1000 stmt.allnoconfig_y = True 1005 stmt.allnoconfig_y = True
1001 1006
1002 else: 1007 else:
1003 _parse_error(line, "unrecognized option", filename, linenr) 1008 _parse_error(line, "unrecognized option", filename, linenr)
1004 1009
1005 elif t0 == T_VISIBLE: 1010 elif t0 == T_VISIBLE:
1006 if not tokens.check(T_IF): 1011 if not tokens.check(T_IF):
1007 _parse_error(line, 'expected "if" after "visible"', 1012 _parse_error(line, 'expected "if" after "visible"',
1008 filename, linenr) 1013 filename, linenr)
1009 if not isinstance(stmt, Menu): 1014 if not isinstance(stmt, Menu):
1010 _parse_error(line, 1015 _parse_error(line,
1011 "'visible if' is only valid for menus", 1016 "'visible if' is only valid for menus",
1012 filename, linenr) 1017 filename, linenr)
1013 1018
1014 parsed_deps = self._parse_expr(tokens, stmt, line, filename, 1019 parsed_deps = self._parse_expr(tokens, stmt, line, filename,
1015 linenr) 1020 linenr)
1016 stmt.visible_if_expr = _make_and(stmt.visible_if_expr, 1021 stmt.visible_if_expr = _make_and(stmt.visible_if_expr,
1017 parsed_deps) 1022 parsed_deps)
1018 1023
1019 elif t0 == T_OPTIONAL: 1024 elif t0 == T_OPTIONAL:
1020 if not isinstance(stmt, Choice): 1025 if not isinstance(stmt, Choice):
1021 _parse_error(line, 1026 _parse_error(line,
1022 '"optional" is only valid for choices', 1027 '"optional" is only valid for choices',
1023 filename, 1028 filename,
1024 linenr) 1029 linenr)
1025 stmt.optional = True 1030 stmt.optional = True
1026 1031
1027 else: 1032 else:
1028 # See comment in Config.__init__() 1033 # See comment in Config.__init__()
1029 self.end_line = line 1034 self.end_line = line
1030 self.end_line_tokens = tokens 1035 self.end_line_tokens = tokens
1031 break 1036 break
1032 1037
1033 # Done parsing properties. Now propagate 'depends on' and enclosing 1038 # Done parsing properties. Now propagate 'depends on' and enclosing
1034 # menu/if dependencies to expressions. 1039 # menu/if dependencies to expressions.
1035 1040
1036 # The set of symbols referenced directly by the statement plus all 1041 # The set of symbols referenced directly by the statement plus all
1037 # symbols referenced by enclosing menus and ifs 1042 # symbols referenced by enclosing menus and ifs
1038 stmt.all_referenced_syms = stmt.referenced_syms | _get_expr_syms(deps) 1043 stmt.all_referenced_syms = stmt.referenced_syms | _get_expr_syms(deps)
1039 1044
1040 # Save original dependencies from enclosing menus and ifs 1045 # Save original dependencies from enclosing menus and ifs
1041 stmt.deps_from_containing = deps 1046 stmt.deps_from_containing = deps
1042 1047
1043 if isinstance(stmt, (Menu, Comment)): 1048 if isinstance(stmt, (Menu, Comment)):
1044 stmt.dep_expr = _make_and(stmt.orig_deps, deps) 1049 stmt.dep_expr = _make_and(stmt.orig_deps, deps)
1045 else: 1050 else:
1046 # Symbol or Choice 1051 # Symbol or Choice
1047 1052
1048 # See comment for 'menu_dep' 1053 # See comment for 'menu_dep'
1049 stmt.menu_dep = depends_on_expr 1054 stmt.menu_dep = depends_on_expr
1050 1055
1051 # Propagate dependencies to prompts 1056 # Propagate dependencies to prompts
1052 1057
1053 if new_prompt is not None: 1058 if new_prompt is not None:
1054 # Propagate 'visible if' dependencies from enclosing menus 1059 # Propagate 'visible if' dependencies from enclosing menus
1055 prompt, cond_expr = new_prompt 1060 prompt, cond_expr = new_prompt
1056 cond_expr = _make_and(cond_expr, visible_if_deps) 1061 cond_expr = _make_and(cond_expr, visible_if_deps)
1057 # Propagate 'depends on' dependencies 1062 # Propagate 'depends on' dependencies
1058 new_prompt = (prompt, _make_and(cond_expr, depends_on_expr)) 1063 new_prompt = (prompt, _make_and(cond_expr, depends_on_expr))
1059 # Save original 1064 # Save original
1060 stmt.orig_prompts.append(new_prompt) 1065 stmt.orig_prompts.append(new_prompt)
1061 # Finalize with dependencies from enclosing menus and ifs 1066 # Finalize with dependencies from enclosing menus and ifs
1062 stmt.prompts.append((new_prompt[0], 1067 stmt.prompts.append((new_prompt[0],
1063 _make_and(new_prompt[1], deps))) 1068 _make_and(new_prompt[1], deps)))
1064 1069
1065 # Propagate dependencies to defaults 1070 # Propagate dependencies to defaults
1066 1071
1067 # Propagate 'depends on' dependencies 1072 # Propagate 'depends on' dependencies
1068 new_def_exprs = [(val_expr, _make_and(cond_expr, depends_on_expr)) 1073 new_def_exprs = [(val_expr, _make_and(cond_expr, depends_on_expr))
1069 for val_expr, cond_expr in new_def_exprs] 1074 for val_expr, cond_expr in new_def_exprs]
1070 # Save original 1075 # Save original
1071 stmt.orig_def_exprs.extend(new_def_exprs) 1076 stmt.orig_def_exprs.extend(new_def_exprs)
1072 # Finalize with dependencies from enclosing menus and ifs 1077 # Finalize with dependencies from enclosing menus and ifs
1073 stmt.def_exprs.extend([(val_expr, _make_and(cond_expr, deps)) 1078 stmt.def_exprs.extend([(val_expr, _make_and(cond_expr, deps))
1074 for val_expr, cond_expr in new_def_exprs]) 1079 for val_expr, cond_expr in new_def_exprs])
1075 1080
1076 # Propagate dependencies to selects 1081 # Propagate dependencies to selects
1077 1082
1078 # Only symbols can select 1083 # Only symbols can select
1079 if isinstance(stmt, Symbol): 1084 if isinstance(stmt, Symbol):
1080 # Propagate 'depends on' dependencies 1085 # Propagate 'depends on' dependencies
1081 new_selects = [(target, _make_and(cond_expr, depends_on_expr)) 1086 new_selects = [(target, _make_and(cond_expr, depends_on_expr))
1082 for target, cond_expr in new_selects] 1087 for target, cond_expr in new_selects]
1083 # Save original 1088 # Save original
1084 stmt.orig_selects.extend(new_selects) 1089 stmt.orig_selects.extend(new_selects)
1085 # Finalize with dependencies from enclosing menus and ifs 1090 # Finalize with dependencies from enclosing menus and ifs
1086 for target, cond in new_selects: 1091 for target, cond in new_selects:
1087 target.rev_dep = _make_or(target.rev_dep, 1092 target.rev_dep = _make_or(target.rev_dep,
1088 _make_and(stmt, 1093 _make_and(stmt,
1089 _make_and(cond, deps))) 1094 _make_and(cond, deps)))
1090 1095
1091 def _parse_expr(self, feed, cur_item, line, filename=None, linenr=None, 1096 def _parse_expr(self, feed, cur_item, line, filename=None, linenr=None,
1092 transform_m=True): 1097 transform_m=True):
1093 """Parses an expression from the tokens in 'feed' using a simple 1098 """Parses an expression from the tokens in 'feed' using a simple
1094 top-down approach. The result has the form 1099 top-down approach. The result has the form
1095 '(<operator>, [<parsed operands>])', where <operator> is e.g. 1100 '(<operator>, [<parsed operands>])', where <operator> is e.g.
1096 kconfiglib.AND. If there is only one operand (i.e., no && or ||), then 1101 kconfiglib.AND. If there is only one operand (i.e., no && or ||), then
1097 the operand is returned directly. This also goes for subexpressions. 1102 the operand is returned directly. This also goes for subexpressions.
1098 1103
1099 feed: _Feed instance containing the tokens for the expression. 1104 feed: _Feed instance containing the tokens for the expression.
1100 1105
1101 cur_item: The item (Symbol, Choice, Menu, or Comment) currently being 1106 cur_item: The item (Symbol, Choice, Menu, or Comment) currently being
1102 parsed, or None if we're not parsing an item. Used for recording 1107 parsed, or None if we're not parsing an item. Used for recording
1103 references to symbols. 1108 references to symbols.
1104 1109
1105 line: The line containing the expression being parsed. 1110 line: The line containing the expression being parsed.
1106 1111
1107 filename (default: None): The file containing the expression. 1112 filename (default: None): The file containing the expression.
1108 1113
1109 linenr (default: None): The line number containing the expression. 1114 linenr (default: None): The line number containing the expression.
1110 1115
1111 transform_m (default: False): Determines if 'm' should be rewritten to 1116 transform_m (default: False): Determines if 'm' should be rewritten to
1112 'm && MODULES' -- see parse_val_and_cond(). 1117 'm && MODULES' -- see parse_val_and_cond().
1113 1118
1114 Expression grammar, in decreasing order of precedence: 1119 Expression grammar, in decreasing order of precedence:
1115 1120
1116 <expr> -> <symbol> 1121 <expr> -> <symbol>
1117 <symbol> '=' <symbol> 1122 <symbol> '=' <symbol>
1118 <symbol> '!=' <symbol> 1123 <symbol> '!=' <symbol>
1119 '(' <expr> ')' 1124 '(' <expr> ')'
1120 '!' <expr> 1125 '!' <expr>
1121 <expr> '&&' <expr> 1126 <expr> '&&' <expr>
1122 <expr> '||' <expr>""" 1127 <expr> '||' <expr>"""
1123 1128
1124 # Use instance variables to avoid having to pass these as arguments 1129 # Use instance variables to avoid having to pass these as arguments
1125 # through the top-down parser in _parse_expr_rec(), which is tedious 1130 # through the top-down parser in _parse_expr_rec(), which is tedious
1126 # and obfuscates the code. A profiler run shows no noticeable 1131 # and obfuscates the code. A profiler run shows no noticeable
1127 # performance difference. 1132 # performance difference.
1128 self._cur_item = cur_item 1133 self._cur_item = cur_item
1129 self._transform_m = transform_m 1134 self._transform_m = transform_m
1130 self._line = line 1135 self._line = line
1131 self._filename = filename 1136 self._filename = filename
1132 self._linenr = linenr 1137 self._linenr = linenr
1133 1138
1134 return self._parse_expr_rec(feed) 1139 return self._parse_expr_rec(feed)
1135 1140
1136 def _parse_expr_rec(self, feed): 1141 def _parse_expr_rec(self, feed):
1137 or_term = self._parse_or_term(feed) 1142 or_term = self._parse_or_term(feed)
1138 if not feed.check(T_OR): 1143 if not feed.check(T_OR):
1139 # Common case -- no need for an OR node since it's just a single 1144 # Common case -- no need for an OR node since it's just a single
1140 # operand 1145 # operand
1141 return or_term 1146 return or_term
1142 or_terms = [or_term, self._parse_or_term(feed)] 1147 or_terms = [or_term, self._parse_or_term(feed)]
1143 while feed.check(T_OR): 1148 while feed.check(T_OR):
1144 or_terms.append(self._parse_or_term(feed)) 1149 or_terms.append(self._parse_or_term(feed))
1145 return (OR, or_terms) 1150 return (OR, or_terms)
1146 1151
1147 def _parse_or_term(self, feed): 1152 def _parse_or_term(self, feed):
1148 and_term = self._parse_factor(feed) 1153 and_term = self._parse_factor(feed)
1149 if not feed.check(T_AND): 1154 if not feed.check(T_AND):
1150 # Common case -- no need for an AND node since it's just a single 1155 # Common case -- no need for an AND node since it's just a single
1151 # operand 1156 # operand
1152 return and_term 1157 return and_term
1153 and_terms = [and_term, self._parse_factor(feed)] 1158 and_terms = [and_term, self._parse_factor(feed)]
1154 while feed.check(T_AND): 1159 while feed.check(T_AND):
1155 and_terms.append(self._parse_factor(feed)) 1160 and_terms.append(self._parse_factor(feed))
1156 return (AND, and_terms) 1161 return (AND, and_terms)
1157 1162
1158 def _parse_factor(self, feed): 1163 def _parse_factor(self, feed):
1159 token = feed.get_next() 1164 token = feed.get_next()
1160 1165
1161 if isinstance(token, (Symbol, str)): 1166 if isinstance(token, (Symbol, str)):
1162 if self._cur_item is not None and isinstance(token, Symbol): 1167 if self._cur_item is not None and isinstance(token, Symbol):
1163 self._cur_item.referenced_syms.add(token) 1168 self._cur_item.referenced_syms.add(token)
1164 1169
1165 next_token = feed.peek_next() 1170 next_token = feed.peek_next()
1166 # For conditional expressions ('depends on <expr>', 1171 # For conditional expressions ('depends on <expr>',
1167 # '... if <expr>', # etc.), "m" and m are rewritten to 1172 # '... if <expr>', # etc.), "m" and m are rewritten to
1168 # "m" && MODULES. 1173 # "m" && MODULES.
1169 if next_token != T_EQUAL and next_token != T_UNEQUAL: 1174 if next_token != T_EQUAL and next_token != T_UNEQUAL:
1170 if self._transform_m and (token is self.m or token == "m"): 1175 if self._transform_m and (token is self.m or token == "m"):
1171 return (AND, ["m", self._sym_lookup("MODULES")]) 1176 return (AND, ["m", self._sym_lookup("MODULES")])
1172 return token 1177 return token
1173 1178
1174 relation = EQUAL if (feed.get_next() == T_EQUAL) else UNEQUAL 1179 relation = EQUAL if (feed.get_next() == T_EQUAL) else UNEQUAL
1175 token_2 = feed.get_next() 1180 token_2 = feed.get_next()
1176 if self._cur_item is not None and isinstance(token_2, Symbol): 1181 if self._cur_item is not None and isinstance(token_2, Symbol):
1177 self._cur_item.referenced_syms.add(token_2) 1182 self._cur_item.referenced_syms.add(token_2)
1178 return (relation, token, token_2) 1183 return (relation, token, token_2)
1179 1184
1180 if token == T_NOT: 1185 if token == T_NOT:
1181 return (NOT, self._parse_factor(feed)) 1186 return (NOT, self._parse_factor(feed))
1182 1187
1183 if token == T_OPEN_PAREN: 1188 if token == T_OPEN_PAREN:
1184 expr_parse = self._parse_expr_rec(feed) 1189 expr_parse = self._parse_expr_rec(feed)
1185 if not feed.check(T_CLOSE_PAREN): 1190 if not feed.check(T_CLOSE_PAREN):
1186 _parse_error(self._line, "missing end parenthesis", 1191 _parse_error(self._line, "missing end parenthesis",
1187 self._filename, self._linenr) 1192 self._filename, self._linenr)
1188 return expr_parse 1193 return expr_parse
1189 1194
1190 _parse_error(self._line, "malformed expression", self._filename, 1195 _parse_error(self._line, "malformed expression", self._filename,
1191 self._linenr) 1196 self._linenr)
1192 1197
1193 def _tokenize(self, s, for_eval, filename=None, linenr=None): 1198 def _tokenize(self, s, for_eval, filename=None, linenr=None):
1194 """Returns a _Feed instance containing tokens derived from the string 1199 """Returns a _Feed instance containing tokens derived from the string
1195 's'. Registers any new symbols encountered (via _sym_lookup()). 1200 's'. Registers any new symbols encountered (via _sym_lookup()).
1196 1201
1197 (I experimented with a pure regular expression implementation, but it 1202 (I experimented with a pure regular expression implementation, but it
1198 came out slower, less readable, and wouldn't have been as flexible.) 1203 came out slower, less readable, and wouldn't have been as flexible.)
1199 1204
1200 for_eval: True when parsing an expression for a call to Config.eval(), 1205 for_eval: True when parsing an expression for a call to Config.eval(),
1201 in which case we should not treat the first token specially nor 1206 in which case we should not treat the first token specially nor
1202 register new symbols.""" 1207 register new symbols."""
1203 1208
1204 s = s.strip() 1209 s = s.strip()
1205 if s == "" or s[0] == "#": 1210 if s == "" or s[0] == "#":
1206 return _Feed([]) 1211 return _Feed([])
1207 1212
1208 if for_eval: 1213 if for_eval:
1209 previous = None # The previous token seen 1214 previous = None # The previous token seen
1210 tokens = [] 1215 tokens = []
1211 i = 0 # The current index in the string being tokenized 1216 i = 0 # The current index in the string being tokenized
1212 1217
1213 else: 1218 else:
1214 # The initial word on a line is parsed specially. Let 1219 # The initial word on a line is parsed specially. Let
1215 # command_chars = [A-Za-z0-9_]. Then 1220 # command_chars = [A-Za-z0-9_]. Then
1216 # - leading non-command_chars characters are ignored, and 1221 # - leading non-command_chars characters are ignored, and
1217 # - the first token consists the following one or more 1222 # - the first token consists the following one or more
1218 # command_chars characters. 1223 # command_chars characters.
1219 # This is why things like "----help--" are accepted. 1224 # This is why things like "----help--" are accepted.
1220 initial_token_match = _initial_token_re_match(s) 1225 initial_token_match = _initial_token_re_match(s)
1221 if initial_token_match is None: 1226 if initial_token_match is None:
1222 return _Feed([]) 1227 return _Feed([])
1223 keyword = _get_keyword(initial_token_match.group(1)) 1228 keyword = _get_keyword(initial_token_match.group(1))
1224 if keyword == T_HELP: 1229 if keyword == T_HELP:
1225 # Avoid junk after "help", e.g. "---", being registered as a 1230 # Avoid junk after "help", e.g. "---", being registered as a
1226 # symbol 1231 # symbol
1227 return _Feed([T_HELP]) 1232 return _Feed([T_HELP])
1228 if keyword is None: 1233 if keyword is None:
1229 # We expect a keyword as the first token 1234 # We expect a keyword as the first token
1230 _tokenization_error(s, filename, linenr) 1235 _tokenization_error(s, filename, linenr)
1231 1236
1232 previous = keyword 1237 previous = keyword
1233 tokens = [keyword] 1238 tokens = [keyword]
1234 # The current index in the string being tokenized 1239 # The current index in the string being tokenized
1235 i = initial_token_match.end() 1240 i = initial_token_match.end()
1236 1241
1237 # _tokenize() is a hotspot during parsing, and this speeds things up a 1242 # _tokenize() is a hotspot during parsing, and this speeds things up a
1238 # bit 1243 # bit
1239 strlen = len(s) 1244 strlen = len(s)
1240 append = tokens.append 1245 append = tokens.append
1241 1246
1242 # Main tokenization loop. (Handles tokens past the first one.) 1247 # Main tokenization loop. (Handles tokens past the first one.)
1243 while i < strlen: 1248 while i < strlen:
1244 # Test for an identifier/keyword preceded by whitespace first; this 1249 # Test for an identifier/keyword preceded by whitespace first; this
1245 # is the most common case. 1250 # is the most common case.
1246 id_keyword_match = _id_keyword_re_match(s, i) 1251 id_keyword_match = _id_keyword_re_match(s, i)
1247 if id_keyword_match: 1252 if id_keyword_match:
1248 # We have an identifier or keyword. The above also stripped any 1253 # We have an identifier or keyword. The above also stripped any
1249 # whitespace for us. 1254 # whitespace for us.
1250 name = id_keyword_match.group(1) 1255 name = id_keyword_match.group(1)
1251 # Jump past it 1256 # Jump past it
1252 i = id_keyword_match.end() 1257 i = id_keyword_match.end()
1253 1258
1254 keyword = _get_keyword(name) 1259 keyword = _get_keyword(name)
1255 if keyword is not None: 1260 if keyword is not None:
1256 # It's a keyword 1261 # It's a keyword
1257 append(keyword) 1262 append(keyword)
1258 elif previous in STRING_LEX: 1263 elif previous in STRING_LEX:
1259 # What would ordinarily be considered an identifier is 1264 # What would ordinarily be considered an identifier is
1260 # treated as a string after certain tokens 1265 # treated as a string after certain tokens
1261 append(name) 1266 append(name)
1262 else: 1267 else:
1263 # It's a symbol name. _sym_lookup() will take care of 1268 # It's a symbol name. _sym_lookup() will take care of
1264 # allocating a new Symbol instance if it's the first time 1269 # allocating a new Symbol instance if it's the first time
1265 # we see it. 1270 # we see it.
1266 sym = self._sym_lookup(name, for_eval) 1271 sym = self._sym_lookup(name, for_eval)
1267 1272
1268 if previous == T_CONFIG or previous == T_MENUCONFIG: 1273 if previous == T_CONFIG or previous == T_MENUCONFIG:
1269 # If the previous token is T_(MENU)CONFIG 1274 # If the previous token is T_(MENU)CONFIG
1270 # ("(menu)config"), we're tokenizing the first line of 1275 # ("(menu)config"), we're tokenizing the first line of
1271 # a symbol definition, and should remember this as a 1276 # a symbol definition, and should remember this as a
1272 # location where the symbol is defined 1277 # location where the symbol is defined
1273 sym.def_locations.append((filename, linenr)) 1278 sym.def_locations.append((filename, linenr))
1274 else: 1279 else:
1275 # Otherwise, it's a reference to the symbol 1280 # Otherwise, it's a reference to the symbol
1276 sym.ref_locations.append((filename, linenr)) 1281 sym.ref_locations.append((filename, linenr))
1277 1282
1278 append(sym) 1283 append(sym)
1279 1284
1280 else: 1285 else:
1281 # Not an identifier/keyword 1286 # Not an identifier/keyword
1282 1287
1283 while i < strlen and s[i].isspace(): 1288 while i < strlen and s[i].isspace():
1284 i += 1 1289 i += 1
1285 if i == strlen: 1290 if i == strlen:
1286 break 1291 break
1287 c = s[i] 1292 c = s[i]
1288 i += 1 1293 i += 1
1289 1294
1290 # String literal (constant symbol) 1295 # String literal (constant symbol)
1291 if c == '"' or c == "'": 1296 if c == '"' or c == "'":
1292 if "\\" in s: 1297 if "\\" in s:
1293 # Slow path: This could probably be sped up, but it's a 1298 # Slow path: This could probably be sped up, but it's a
1294 # very unusual case anyway. 1299 # very unusual case anyway.
1295 quote = c 1300 quote = c
1296 val = "" 1301 val = ""
1297 while 1: 1302 while 1:
1298 if i >= len(s): 1303 if i >= len(s):
1299 _tokenization_error(s, filename, linenr) 1304 _tokenization_error(s, filename, linenr)
1300 c = s[i] 1305 c = s[i]
1301 if c == quote: 1306 if c == quote:
1302 break 1307 break
1303 if c == "\\": 1308 if c == "\\":
1304 if i + 1 >= len(s): 1309 if i + 1 >= len(s):
1305 _tokenization_error(s, filename, linenr) 1310 _tokenization_error(s, filename, linenr)
1306 val += s[i + 1] 1311 val += s[i + 1]
1307 i += 2 1312 i += 2
1308 else: 1313 else:
1309 val += c 1314 val += c
1310 i += 1 1315 i += 1
1311 i += 1 1316 i += 1
1312 append(val) 1317 append(val)
1313 else: 1318 else:
1314 # Fast path: If the string contains no backslashes 1319 # Fast path: If the string contains no backslashes
1315 # (almost always) we can simply look for the matching 1320 # (almost always) we can simply look for the matching
1316 # quote. 1321 # quote.
1317 end = s.find(c, i) 1322 end = s.find(c, i)
1318 if end == -1: 1323 if end == -1:
1319 _tokenization_error(s, filename, linenr) 1324 _tokenization_error(s, filename, linenr)
1320 append(s[i:end]) 1325 append(s[i:end])
1321 i = end + 1 1326 i = end + 1
1322 1327
1323 elif c == "&": 1328 elif c == "&":
1324 # Invalid characters are ignored 1329 # Invalid characters are ignored
1325 if i >= len(s) or s[i] != "&": continue 1330 if i >= len(s) or s[i] != "&": continue
1326 append(T_AND) 1331 append(T_AND)
1327 i += 1 1332 i += 1
1328 1333
1329 elif c == "|": 1334 elif c == "|":
1330 # Invalid characters are ignored 1335 # Invalid characters are ignored
1331 if i >= len(s) or s[i] != "|": continue 1336 if i >= len(s) or s[i] != "|": continue
1332 append(T_OR) 1337 append(T_OR)
1333 i += 1 1338 i += 1
1334 1339
1335 elif c == "!": 1340 elif c == "!":
1336 if i < len(s) and s[i] == "=": 1341 if i < len(s) and s[i] == "=":
1337 append(T_UNEQUAL) 1342 append(T_UNEQUAL)
1338 i += 1 1343 i += 1
1339 else: 1344 else:
1340 append(T_NOT) 1345 append(T_NOT)
1341 1346
1342 elif c == "=": append(T_EQUAL) 1347 elif c == "=": append(T_EQUAL)
1343 elif c == "(": append(T_OPEN_PAREN) 1348 elif c == "(": append(T_OPEN_PAREN)
1344 elif c == ")": append(T_CLOSE_PAREN) 1349 elif c == ")": append(T_CLOSE_PAREN)
1345 elif c == "#": break # Comment 1350 elif c == "#": break # Comment
1346 1351
1347 else: continue # Invalid characters are ignored 1352 else: continue # Invalid characters are ignored
1348 1353
1349 previous = tokens[-1] 1354 previous = tokens[-1]
1350 1355
1351 return _Feed(tokens) 1356 return _Feed(tokens)
1352 1357
1353 def _sym_lookup(self, name, for_eval=False): 1358 def _sym_lookup(self, name, for_eval=False):
1354 """Fetches the symbol 'name' from the symbol table, creating and 1359 """Fetches the symbol 'name' from the symbol table, creating and
1355 registering it if it does not exist. If 'for_eval' is True, the symbol 1360 registering it if it does not exist. If 'for_eval' is True, the symbol
1356 won't be added to the symbol table if it does not exist -- this is for 1361 won't be added to the symbol table if it does not exist -- this is for
1357 Config.eval().""" 1362 Config.eval()."""
1358 if name in self.syms: 1363 if name in self.syms:
1359 return self.syms[name] 1364 return self.syms[name]
1360 1365
1361 new_sym = Symbol() 1366 new_sym = Symbol()
1362 new_sym.config = self 1367 new_sym.config = self
1363 new_sym.name = name 1368 new_sym.name = name
1364 if for_eval: 1369 if for_eval:
1365 self._warn("no symbol {0} in configuration".format(name)) 1370 self._warn("no symbol {0} in configuration".format(name))
1366 else: 1371 else:
1367 self.syms[name] = new_sym 1372 self.syms[name] = new_sym
1368 return new_sym 1373 return new_sym
1369 1374
1370 # 1375 #
1371 # Expression evaluation 1376 # Expression evaluation
1372 # 1377 #
1373 1378
1374 def _eval_expr(self, expr): 1379 def _eval_expr(self, expr):
1375 """Evaluates an expression to "n", "m", or "y".""" 1380 """Evaluates an expression to "n", "m", or "y"."""
1376 1381
1377 # Handles e.g. an "x if y" condition where the "if y" part is missing. 1382 # Handles e.g. an "x if y" condition where the "if y" part is missing.
1378 if expr is None: 1383 if expr is None:
1379 return "y" 1384 return "y"
1380 1385
1381 res = self._eval_expr_rec(expr) 1386 res = self._eval_expr_rec(expr)
1382 if res == "m": 1387 if res == "m":
1383 # Promote "m" to "y" if we're running without modules. 1388 # Promote "m" to "y" if we're running without modules.
1384 # 1389 #
1385 # Internally, "m" is often rewritten to "m" && MODULES by both the 1390 # Internally, "m" is often rewritten to "m" && MODULES by both the
1386 # C implementation and Kconfiglib, which takes care of cases where 1391 # C implementation and Kconfiglib, which takes care of cases where
1387 # "m" should be demoted to "n" instead. 1392 # "m" should be demoted to "n" instead.
1388 modules_sym = self.syms.get("MODULES") 1393 modules_sym = self.syms.get("MODULES")
1389 if modules_sym is None or modules_sym.get_value() != "y": 1394 if modules_sym is None or modules_sym.get_value() != "y":
1390 return "y" 1395 return "y"
1391 return res 1396 return res
1392 1397
1393 def _eval_expr_rec(self, expr): 1398 def _eval_expr_rec(self, expr):
1394 if isinstance(expr, Symbol): 1399 if isinstance(expr, Symbol):
1395 # Non-bool/tristate symbols are always "n" in a tristate sense, 1400 # Non-bool/tristate symbols are always "n" in a tristate sense,
1396 # regardless of their value 1401 # regardless of their value
1397 if expr.type != BOOL and expr.type != TRISTATE: 1402 if expr.type != BOOL and expr.type != TRISTATE:
1398 return "n" 1403 return "n"
1399 return expr.get_value() 1404 return expr.get_value()
1400 1405
1401 if isinstance(expr, str): 1406 if isinstance(expr, str):
1402 return expr if (expr == "y" or expr == "m") else "n" 1407 return expr if (expr == "y" or expr == "m") else "n"
1403 1408
1404 # Ordered by frequency 1409 # Ordered by frequency
1405 1410
1406 if expr[0] == AND: 1411 if expr[0] == AND:
1407 res = "y" 1412 res = "y"
1408 for subexpr in expr[1]: 1413 for subexpr in expr[1]:
1409 ev = self._eval_expr_rec(subexpr) 1414 ev = self._eval_expr_rec(subexpr)
1410 # Return immediately upon discovering an "n" term 1415 # Return immediately upon discovering an "n" term
1411 if ev == "n": 1416 if ev == "n":
1412 return "n" 1417 return "n"
1413 if ev == "m": 1418 if ev == "m":
1414 res = "m" 1419 res = "m"
1415 # 'res' is either "m" or "y" here; we already handled the 1420 # 'res' is either "m" or "y" here; we already handled the
1416 # short-circuiting "n" case in the loop. 1421 # short-circuiting "n" case in the loop.
1417 return res 1422 return res
1418 1423
1419 if expr[0] == NOT: 1424 if expr[0] == NOT:
1420 ev = self._eval_expr_rec(expr[1]) 1425 ev = self._eval_expr_rec(expr[1])
1421 if ev == "y": 1426 if ev == "y":
1422 return "n" 1427 return "n"
1423 return "y" if (ev == "n") else "m" 1428 return "y" if (ev == "n") else "m"
1424 1429
1425 if expr[0] == OR: 1430 if expr[0] == OR:
1426 res = "n" 1431 res = "n"
1427 for subexpr in expr[1]: 1432 for subexpr in expr[1]:
1428 ev = self._eval_expr_rec(subexpr) 1433 ev = self._eval_expr_rec(subexpr)
1429 # Return immediately upon discovering a "y" term 1434 # Return immediately upon discovering a "y" term
1430 if ev == "y": 1435 if ev == "y":
1431 return "y" 1436 return "y"
1432 if ev == "m": 1437 if ev == "m":
1433 res = "m" 1438 res = "m"
1434 # 'res' is either "n" or "m" here; we already handled the 1439 # 'res' is either "n" or "m" here; we already handled the
1435 # short-circuiting "y" case in the loop. 1440 # short-circuiting "y" case in the loop.
1436 return res 1441 return res
1437 1442
1438 if expr[0] == EQUAL: 1443 if expr[0] == EQUAL:
1439 return "y" if (_str_val(expr[1]) == _str_val(expr[2])) else "n" 1444 return "y" if (_str_val(expr[1]) == _str_val(expr[2])) else "n"
1440 1445
1441 if expr[0] == UNEQUAL: 1446 if expr[0] == UNEQUAL:
1442 return "y" if (_str_val(expr[1]) != _str_val(expr[2])) else "n" 1447 return "y" if (_str_val(expr[1]) != _str_val(expr[2])) else "n"
1443 1448
1444 _internal_error("Internal error while evaluating expression: " 1449 _internal_error("Internal error while evaluating expression: "
1445 "unknown operation {0}.".format(expr[0])) 1450 "unknown operation {0}.".format(expr[0]))
1446 1451
1447 def _eval_min(self, e1, e2): 1452 def _eval_min(self, e1, e2):
1448 """Returns the minimum value of the two expressions. Equates None with 1453 """Returns the minimum value of the two expressions. Equates None with
1449 'y'.""" 1454 'y'."""
1450 e1_eval = self._eval_expr(e1) 1455 e1_eval = self._eval_expr(e1)
1451 e2_eval = self._eval_expr(e2) 1456 e2_eval = self._eval_expr(e2)
1452 return e1_eval if tri_less(e1_eval, e2_eval) else e2_eval 1457 return e1_eval if tri_less(e1_eval, e2_eval) else e2_eval
1453 1458
1454 def _eval_max(self, e1, e2): 1459 def _eval_max(self, e1, e2):
1455 """Returns the maximum value of the two expressions. Equates None with 1460 """Returns the maximum value of the two expressions. Equates None with
1456 'y'.""" 1461 'y'."""
1457 e1_eval = self._eval_expr(e1) 1462 e1_eval = self._eval_expr(e1)
1458 e2_eval = self._eval_expr(e2) 1463 e2_eval = self._eval_expr(e2)
1459 return e1_eval if tri_greater(e1_eval, e2_eval) else e2_eval 1464 return e1_eval if tri_greater(e1_eval, e2_eval) else e2_eval
1460 1465
1461 # 1466 #
1462 # Dependency tracking (for caching and invalidation) 1467 # Dependency tracking (for caching and invalidation)
1463 # 1468 #
1464 1469
1465 def _build_dep(self): 1470 def _build_dep(self):
1466 """Populates the Symbol.dep sets, linking the symbol to the symbols 1471 """Populates the Symbol.dep sets, linking the symbol to the symbols
1467 that immediately depend on it in the sense that changing the value of 1472 that immediately depend on it in the sense that changing the value of
1468 the symbol might affect the values of those other symbols. This is used 1473 the symbol might affect the values of those other symbols. This is used
1469 for caching/invalidation purposes. The calculated sets might be larger 1474 for caching/invalidation purposes. The calculated sets might be larger
1470 than necessary as we don't do any complicated analysis of the 1475 than necessary as we don't do any complicated analysis of the
1471 expressions.""" 1476 expressions."""
1472 1477
1473 # Adds 'sym' as a directly dependent symbol to all symbols that appear 1478 # Adds 'sym' as a directly dependent symbol to all symbols that appear
1474 # in the expression 'e' 1479 # in the expression 'e'
1475 def add_expr_deps(e, sym): 1480 def add_expr_deps(e, sym):
1476 for s in _get_expr_syms(e): 1481 for s in _get_expr_syms(e):
1477 s.dep.add(sym) 1482 s.dep.add(sym)
1478 1483
1479 # The directly dependent symbols of a symbol are: 1484 # The directly dependent symbols of a symbol are:
1480 # - Any symbols whose prompts, default values, rev_dep (select 1485 # - Any symbols whose prompts, default values, rev_dep (select
1481 # condition), or ranges depend on the symbol 1486 # condition), or ranges depend on the symbol
1482 # - Any symbols that belong to the same choice statement as the symbol 1487 # - Any symbols that belong to the same choice statement as the symbol
1483 # (these won't be included in 'dep' as that makes the dependency 1488 # (these won't be included in 'dep' as that makes the dependency
1484 # graph unwieldy, but Symbol._get_dependent() will include them) 1489 # graph unwieldy, but Symbol._get_dependent() will include them)
1485 # - Any symbols in a choice statement that depends on the symbol 1490 # - Any symbols in a choice statement that depends on the symbol
1486 for sym in self.syms_iter(): 1491 for sym in self.syms_iter():
1487 for _, e in sym.prompts: 1492 for _, e in sym.prompts:
1488 add_expr_deps(e, sym) 1493 add_expr_deps(e, sym)
1489 1494
1490 for v, e in sym.def_exprs: 1495 for v, e in sym.def_exprs:
1491 add_expr_deps(v, sym) 1496 add_expr_deps(v, sym)
1492 add_expr_deps(e, sym) 1497 add_expr_deps(e, sym)
1493 1498
1494 add_expr_deps(sym.rev_dep, sym) 1499 add_expr_deps(sym.rev_dep, sym)
1495 1500
1496 for l, u, e in sym.ranges: 1501 for l, u, e in sym.ranges:
1497 add_expr_deps(l, sym) 1502 add_expr_deps(l, sym)
1498 add_expr_deps(u, sym) 1503 add_expr_deps(u, sym)
1499 add_expr_deps(e, sym) 1504 add_expr_deps(e, sym)
1500 1505
1501 if sym.is_choice_sym: 1506 if sym.is_choice_sym:
1502 choice = sym.parent 1507 choice = sym.parent
1503 for _, e in choice.prompts: 1508 for _, e in choice.prompts:
1504 add_expr_deps(e, sym) 1509 add_expr_deps(e, sym)
1505 for _, e in choice.def_exprs: 1510 for _, e in choice.def_exprs:
1506 add_expr_deps(e, sym) 1511 add_expr_deps(e, sym)
1507 1512
1508 def _eq_to_sym(self, eq): 1513 def _eq_to_sym(self, eq):
1509 """_expr_depends_on() helper. For (in)equalities of the form sym = y/m 1514 """_expr_depends_on() helper. For (in)equalities of the form sym = y/m
1510 or sym != n, returns sym. For other (in)equalities, returns None.""" 1515 or sym != n, returns sym. For other (in)equalities, returns None."""
1511 relation, left, right = eq 1516 relation, left, right = eq
1512 1517
1513 def transform_y_m_n(item): 1518 def transform_y_m_n(item):
1514 if item is self.y: return "y" 1519 if item is self.y: return "y"
1515 if item is self.m: return "m" 1520 if item is self.m: return "m"
1516 if item is self.n: return "n" 1521 if item is self.n: return "n"
1517 return item 1522 return item
1518 1523
1519 left = transform_y_m_n(left) 1524 left = transform_y_m_n(left)
1520 right = transform_y_m_n(right) 1525 right = transform_y_m_n(right)
1521 1526
1522 # Make sure the symbol (if any) appears to the left 1527 # Make sure the symbol (if any) appears to the left
1523 if not isinstance(left, Symbol): 1528 if not isinstance(left, Symbol):
1524 left, right = right, left 1529 left, right = right, left
1525 if not isinstance(left, Symbol): 1530 if not isinstance(left, Symbol):
1526 return None 1531 return None
1527 if (relation == EQUAL and (right == "y" or right == "m")) or \ 1532 if (relation == EQUAL and (right == "y" or right == "m")) or \
1528 (relation == UNEQUAL and right == "n"): 1533 (relation == UNEQUAL and right == "n"):
1529 return left 1534 return left
1530 return None 1535 return None
1531 1536
1532 def _expr_depends_on(self, expr, sym): 1537 def _expr_depends_on(self, expr, sym):
1533 """Reimplementation of expr_depends_symbol() from mconf.c. Used to 1538 """Reimplementation of expr_depends_symbol() from mconf.c. Used to
1534 determine if a submenu should be implicitly created, which influences 1539 determine if a submenu should be implicitly created, which influences
1535 what items inside choice statements are considered choice items.""" 1540 what items inside choice statements are considered choice items."""
1536 if expr is None: 1541 if expr is None:
1537 return False 1542 return False
1538 1543
1539 def rec(expr): 1544 def rec(expr):
1540 if isinstance(expr, str): 1545 if isinstance(expr, str):
1541 return False 1546 return False
1542 if isinstance(expr, Symbol): 1547 if isinstance(expr, Symbol):
1543 return expr is sym 1548 return expr is sym
1544 1549
1545 if expr[0] in (EQUAL, UNEQUAL): 1550 if expr[0] in (EQUAL, UNEQUAL):
1546 return self._eq_to_sym(expr) is sym 1551 return self._eq_to_sym(expr) is sym
1547 if expr[0] == AND: 1552 if expr[0] == AND:
1548 for and_expr in expr[1]: 1553 for and_expr in expr[1]:
1549 if rec(and_expr): 1554 if rec(and_expr):
1550 return True 1555 return True
1551 return False 1556 return False
1552 1557
1553 return rec(expr) 1558 return rec(expr)
1554 1559
1555 def _invalidate_all(self): 1560 def _invalidate_all(self):
1556 for sym in self.syms_iter(): 1561 for sym in self.syms_iter():
1557 sym._invalidate() 1562 sym._invalidate()
1558 1563
1559 # 1564 #
1560 # Printing and misc. 1565 # Printing and misc.
1561 # 1566 #
1562 1567
1563 def _expand_sym_refs(self, s): 1568 def _expand_sym_refs(self, s):
1564 """Expands $-references to symbols in 's' to symbol values, or to the 1569 """Expands $-references to symbols in 's' to symbol values, or to the
1565 empty string for undefined symbols.""" 1570 empty string for undefined symbols."""
1566 1571
1567 while 1: 1572 while 1:
1568 sym_ref_match = _sym_ref_re_search(s) 1573 sym_ref_match = _sym_ref_re_search(s)
1569 if sym_ref_match is None: 1574 if sym_ref_match is None:
1570 return s 1575 return s
1571 1576
1572 sym_name = sym_ref_match.group(0)[1:] 1577 sym_name = sym_ref_match.group(0)[1:]
1573 sym = self.syms.get(sym_name) 1578 sym = self.syms.get(sym_name)
1574 expansion = "" if sym is None else sym.get_value() 1579 expansion = "" if sym is None else sym.get_value()
1575 1580
1576 s = s[:sym_ref_match.start()] + \ 1581 s = s[:sym_ref_match.start()] + \
1577 expansion + \ 1582 expansion + \
1578 s[sym_ref_match.end():] 1583 s[sym_ref_match.end():]
1579 1584
1580 def _expr_val_str(self, expr, no_value_str="(none)", 1585 def _expr_val_str(self, expr, no_value_str="(none)",
1581 get_val_instead_of_eval=False): 1586 get_val_instead_of_eval=False):
1582 """Printing helper. Returns a string with 'expr' and its value. 1587 """Printing helper. Returns a string with 'expr' and its value.
1583 1588
1584 no_value_str: String to return when 'expr' is missing (None). 1589 no_value_str: String to return when 'expr' is missing (None).
1585 1590
1586 get_val_instead_of_eval: Assume 'expr' is a symbol or string (constant 1591 get_val_instead_of_eval: Assume 'expr' is a symbol or string (constant
1587 symbol) and get its value directly instead of evaluating it to a 1592 symbol) and get its value directly instead of evaluating it to a
1588 tristate value.""" 1593 tristate value."""
1589 1594
1590 if expr is None: 1595 if expr is None:
1591 return no_value_str 1596 return no_value_str
1592 1597
1593 if get_val_instead_of_eval: 1598 if get_val_instead_of_eval:
1594 if isinstance(expr, str): 1599 if isinstance(expr, str):
1595 return _expr_to_str(expr) 1600 return _expr_to_str(expr)
1596 val = expr.get_value() 1601 val = expr.get_value()
1597 else: 1602 else:
1598 val = self._eval_expr(expr) 1603 val = self._eval_expr(expr)
1599 1604
1600 return "{0} (value: {1})".format(_expr_to_str(expr), _expr_to_str(val)) 1605 return "{0} (value: {1})".format(_expr_to_str(expr), _expr_to_str(val))
1601 1606
1602 def _get_sym_or_choice_str(self, sc): 1607 def _get_sym_or_choice_str(self, sc):
1603 """Symbols and choices have many properties in common, so we factor out 1608 """Symbols and choices have many properties in common, so we factor out
1604 common __str__() stuff here. "sc" is short for "symbol or choice".""" 1609 common __str__() stuff here. "sc" is short for "symbol or choice"."""
1605 1610
1606 # As we deal a lot with string representations here, use some 1611 # As we deal a lot with string representations here, use some
1607 # convenient shorthand: 1612 # convenient shorthand:
1608 s = _expr_to_str 1613 s = _expr_to_str
1609 1614
1610 # 1615 #
1611 # Common symbol/choice properties 1616 # Common symbol/choice properties
1612 # 1617 #
1613 1618
1614 user_val_str = "(no user value)" if sc.user_val is None else \ 1619 user_val_str = "(no user value)" if sc.user_val is None else \
1615 s(sc.user_val) 1620 s(sc.user_val)
1616 1621
1617 # Build prompts string 1622 # Build prompts string
1618 if not sc.prompts: 1623 if not sc.prompts:
1619 prompts_str = " (no prompts)" 1624 prompts_str = " (no prompts)"
1620 else: 1625 else:
1621 prompts_str_rows = [] 1626 prompts_str_rows = []
1622 for prompt, cond_expr in sc.orig_prompts: 1627 for prompt, cond_expr in sc.orig_prompts:
1623 if cond_expr is None: 1628 if cond_expr is None:
1624 prompts_str_rows.append(' "{0}"'.format(prompt)) 1629 prompts_str_rows.append(' "{0}"'.format(prompt))
1625 else: 1630 else:
1626 prompts_str_rows.append( 1631 prompts_str_rows.append(
1627 ' "{0}" if {1}'.format(prompt, 1632 ' "{0}" if {1}'.format(prompt,
1628 self._expr_val_str(cond_expr))) 1633 self._expr_val_str(cond_expr)))
1629 prompts_str = "\n".join(prompts_str_rows) 1634 prompts_str = "\n".join(prompts_str_rows)
1630 1635
1631 # Build locations string 1636 # Build locations string
1632 if not sc.def_locations: 1637 if not sc.def_locations:
1633 locations_str = "(no locations)" 1638 locations_str = "(no locations)"
1634 else: 1639 else:
1635 locations_str = " ".join(["{0}:{1}".format(filename, linenr) for 1640 locations_str = " ".join(["{0}:{1}".format(filename, linenr) for
1636 (filename, linenr) in sc.def_locations]) 1641 (filename, linenr) in sc.def_locations])
1637 1642
1638 # Build additional-dependencies-from-menus-and-ifs string 1643 # Build additional-dependencies-from-menus-and-ifs string
1639 additional_deps_str = " " + \ 1644 additional_deps_str = " " + \
1640 self._expr_val_str(sc.deps_from_containing, 1645 self._expr_val_str(sc.deps_from_containing,
1641 "(no additional dependencies)") 1646 "(no additional dependencies)")
1642 1647
1643 # 1648 #
1644 # Symbol-specific stuff 1649 # Symbol-specific stuff
1645 # 1650 #
1646 1651
1647 if isinstance(sc, Symbol): 1652 if isinstance(sc, Symbol):
1648 # Build ranges string 1653 # Build ranges string
1649 if isinstance(sc, Symbol): 1654 if isinstance(sc, Symbol):
1650 if not sc.ranges: 1655 if not sc.ranges:
1651 ranges_str = " (no ranges)" 1656 ranges_str = " (no ranges)"
1652 else: 1657 else:
1653 ranges_str_rows = [] 1658 ranges_str_rows = []
1654 for l, u, cond_expr in sc.ranges: 1659 for l, u, cond_expr in sc.ranges:
1655 if cond_expr is None: 1660 if cond_expr is None:
1656 ranges_str_rows.append(" [{0}, {1}]".format(s(l), 1661 ranges_str_rows.append(" [{0}, {1}]".format(s(l),
1657 s(u))) 1662 s(u)))
1658 else: 1663 else:
1659 ranges_str_rows.append(" [{0}, {1}] if {2}" 1664 ranges_str_rows.append(" [{0}, {1}] if {2}"
1660 .format(s(l), s(u), 1665 .format(s(l), s(u),
1661 self._expr_val_str(cond_expr))) 1666 self._expr_val_str(cond_expr)))
1662 ranges_str = "\n".join(ranges_str_rows) 1667 ranges_str = "\n".join(ranges_str_rows)
1663 1668
1664 # Build default values string 1669 # Build default values string
1665 if not sc.def_exprs: 1670 if not sc.def_exprs:
1666 defaults_str = " (no default values)" 1671 defaults_str = " (no default values)"
1667 else: 1672 else:
1668 defaults_str_rows = [] 1673 defaults_str_rows = []
1669 for val_expr, cond_expr in sc.orig_def_exprs: 1674 for val_expr, cond_expr in sc.orig_def_exprs:
1670 row_str = " " + self._expr_val_str(val_expr, "(none)", 1675 row_str = " " + self._expr_val_str(val_expr, "(none)",
1671 sc.type == STRING) 1676 sc.type == STRING)
1672 defaults_str_rows.append(row_str) 1677 defaults_str_rows.append(row_str)
1673 defaults_str_rows.append(" Condition: " + 1678 defaults_str_rows.append(" Condition: " +
1674 self._expr_val_str(cond_expr)) 1679 self._expr_val_str(cond_expr))
1675 defaults_str = "\n".join(defaults_str_rows) 1680 defaults_str = "\n".join(defaults_str_rows)
1676 1681
1677 # Build selects string 1682 # Build selects string
1678 if not sc.orig_selects: 1683 if not sc.orig_selects:
1679 selects_str = " (no selects)" 1684 selects_str = " (no selects)"
1680 else: 1685 else:
1681 selects_str_rows = [] 1686 selects_str_rows = []
1682 for target, cond_expr in sc.orig_selects: 1687 for target, cond_expr in sc.orig_selects:
1683 if cond_expr is None: 1688 if cond_expr is None:
1684 selects_str_rows.append(" {0}".format(target.name)) 1689 selects_str_rows.append(" {0}".format(target.name))
1685 else: 1690 else:
1686 selects_str_rows.append( 1691 selects_str_rows.append(
1687 " {0} if {1}".format(target.name, 1692 " {0} if {1}".format(target.name,
1688 self._expr_val_str(cond_expr))) 1693 self._expr_val_str(cond_expr)))
1689 selects_str = "\n".join(selects_str_rows) 1694 selects_str = "\n".join(selects_str_rows)
1690 1695
1691 res = _lines("Symbol " + 1696 res = _lines("Symbol " +
1692 ("(no name)" if sc.name is None else sc.name), 1697 ("(no name)" if sc.name is None else sc.name),
1693 "Type : " + TYPENAME[sc.type], 1698 "Type : " + TYPENAME[sc.type],
1694 "Value : " + s(sc.get_value()), 1699 "Value : " + s(sc.get_value()),
1695 "User value : " + user_val_str, 1700 "User value : " + user_val_str,
1696 "Visibility : " + s(_get_visibility(sc)), 1701 "Visibility : " + s(_get_visibility(sc)),
1697 "Is choice item : " + BOOL_STR[sc.is_choice_sym], 1702 "Is choice item : " + BOOL_STR[sc.is_choice_sym],
1698 "Is defined : " + BOOL_STR[sc.is_defined_], 1703 "Is defined : " + BOOL_STR[sc.is_defined_],
1699 "Is from env. : " + BOOL_STR[sc.is_from_env], 1704 "Is from env. : " + BOOL_STR[sc.is_from_env],
1700 "Is special : " + BOOL_STR[sc.is_special_] + "\n") 1705 "Is special : " + BOOL_STR[sc.is_special_] + "\n")
1701 if sc.ranges: 1706 if sc.ranges:
1702 res += _lines("Ranges:", ranges_str + "\n") 1707 res += _lines("Ranges:", ranges_str + "\n")
1703 res += _lines("Prompts:", 1708 res += _lines("Prompts:",
1704 prompts_str, 1709 prompts_str,
1705 "Default values:", 1710 "Default values:",
1706 defaults_str, 1711 defaults_str,
1707 "Selects:", 1712 "Selects:",
1708 selects_str, 1713 selects_str,
1709 "Reverse (select-related) dependencies:", 1714 "Reverse (select-related) dependencies:",
1710 " (no reverse dependencies)" if sc.rev_dep == "n" 1715 " (no reverse dependencies)" if sc.rev_dep == "n"
1711 else " " + self._expr_val_str(sc.rev_dep), 1716 else " " + self._expr_val_str(sc.rev_dep),
1712 "Additional dependencies from enclosing menus " 1717 "Additional dependencies from enclosing menus "
1713 "and ifs:", 1718 "and ifs:",
1714 additional_deps_str, 1719 additional_deps_str,
1715 "Locations: " + locations_str) 1720 "Locations: " + locations_str)
1716 1721
1717 return res 1722 return res
1718 1723
1719 # 1724 #
1720 # Choice-specific stuff 1725 # Choice-specific stuff
1721 # 1726 #
1722 1727
1723 # Build selected symbol string 1728 # Build selected symbol string
1724 sel = sc.get_selection() 1729 sel = sc.get_selection()
1725 sel_str = "(no selection)" if sel is None else sel.name 1730 sel_str = "(no selection)" if sel is None else sel.name
1726 1731
1727 # Build default values string 1732 # Build default values string
1728 if not sc.def_exprs: 1733 if not sc.def_exprs:
1729 defaults_str = " (no default values)" 1734 defaults_str = " (no default values)"
1730 else: 1735 else:
1731 defaults_str_rows = [] 1736 defaults_str_rows = []
1732 for sym, cond_expr in sc.orig_def_exprs: 1737 for sym, cond_expr in sc.orig_def_exprs:
1733 if cond_expr is None: 1738 if cond_expr is None:
1734 defaults_str_rows.append(" {0}".format(sym.name)) 1739 defaults_str_rows.append(" {0}".format(sym.name))
1735 else: 1740 else:
1736 defaults_str_rows.append(" {0} if {1}".format(sym.name, 1741 defaults_str_rows.append(" {0} if {1}".format(sym.name,
1737 self._expr_val_str(cond_expr))) 1742 self._expr_val_str(cond_expr)))
1738 defaults_str = "\n".join(defaults_str_rows) 1743 defaults_str = "\n".join(defaults_str_rows)
1739 1744
1740 # Build contained symbols string 1745 # Build contained symbols string
1741 names = [sym.name for sym in sc.actual_symbols] 1746 names = [sym.name for sym in sc.actual_symbols]
1742 syms_string = " ".join(names) if names else "(empty)" 1747 syms_string = " ".join(names) if names else "(empty)"
1743 1748
1744 return _lines("Choice", 1749 return _lines("Choice",
1745 "Name (for named choices): " + 1750 "Name (for named choices): " +
1746 ("(no name)" if sc.name is None else sc.name), 1751 ("(no name)" if sc.name is None else sc.name),
1747 "Type : " + TYPENAME[sc.type], 1752 "Type : " + TYPENAME[sc.type],
1748 "Selected symbol : " + sel_str, 1753 "Selected symbol : " + sel_str,
1749 "User value : " + user_val_str, 1754 "User value : " + user_val_str,
1750 "Mode : " + s(sc.get_mode()), 1755 "Mode : " + s(sc.get_mode()),
1751 "Visibility : " + s(_get_visibility(sc)), 1756 "Visibility : " + s(_get_visibility(sc)),
1752 "Optional : " + BOOL_STR[sc.optional], 1757 "Optional : " + BOOL_STR[sc.optional],
1753 "Prompts:", 1758 "Prompts:",
1754 prompts_str, 1759 prompts_str,
1755 "Defaults:", 1760 "Defaults:",
1756 defaults_str, 1761 defaults_str,
1757 "Choice symbols:", 1762 "Choice symbols:",
1758 " " + syms_string, 1763 " " + syms_string,
1759 "Additional dependencies from enclosing menus and " 1764 "Additional dependencies from enclosing menus and "
1760 "ifs:", 1765 "ifs:",
1761 additional_deps_str, 1766 additional_deps_str,
1762 "Locations: " + locations_str) 1767 "Locations: " + locations_str)
1763 1768
1764 def _warn(self, msg, filename=None, linenr=None): 1769 def _warn(self, msg, filename=None, linenr=None):
1765 """For printing warnings to stderr.""" 1770 """For printing warnings to stderr."""
1771 msg = _build_msg("warning: " + msg, filename, linenr)
1766 if self.print_warnings: 1772 if self.print_warnings:
1767 _stderr_msg("warning: " + msg, filename, linenr) 1773 sys.stderr.write(msg + "\n")
1774 self._warnings.append(msg)
1768 1775
1769 class Item(object): 1776 class Item(object):
1770 1777
1771 """Base class for symbols and other Kconfig constructs. Subclasses are 1778 """Base class for symbols and other Kconfig constructs. Subclasses are
1772 Symbol, Choice, Menu, and Comment.""" 1779 Symbol, Choice, Menu, and Comment."""
1773 1780
1774 def is_symbol(self): 1781 def is_symbol(self):
1775 """Returns True if the item is a symbol. Short for 1782 """Returns True if the item is a symbol. Short for
1776 isinstance(item, kconfiglib.Symbol).""" 1783 isinstance(item, kconfiglib.Symbol)."""
1777 return isinstance(self, Symbol) 1784 return isinstance(self, Symbol)
1778 1785
1779 def is_choice(self): 1786 def is_choice(self):
1780 """Returns True if the item is a choice. Short for 1787 """Returns True if the item is a choice. Short for
1781 isinstance(item, kconfiglib.Choice).""" 1788 isinstance(item, kconfiglib.Choice)."""
1782 return isinstance(self, Choice) 1789 return isinstance(self, Choice)
1783 1790
1784 def is_menu(self): 1791 def is_menu(self):
1785 """Returns True if the item is a menu. Short for 1792 """Returns True if the item is a menu. Short for
1786 isinstance(item, kconfiglib.Menu).""" 1793 isinstance(item, kconfiglib.Menu)."""
1787 return isinstance(self, Menu) 1794 return isinstance(self, Menu)
1788 1795
1789 def is_comment(self): 1796 def is_comment(self):
1790 """Returns True if the item is a comment. Short for 1797 """Returns True if the item is a comment. Short for
1791 isinstance(item, kconfiglib.Comment).""" 1798 isinstance(item, kconfiglib.Comment)."""
1792 return isinstance(self, Comment) 1799 return isinstance(self, Comment)
1793 1800
1794 class Symbol(Item): 1801 class Symbol(Item):
1795 1802
1796 """Represents a configuration symbol - e.g. FOO for 1803 """Represents a configuration symbol - e.g. FOO for
1797 1804
1798 config FOO 1805 config FOO
1799 ...""" 1806 ..."""
1800 1807
1801 # 1808 #
1802 # Public interface 1809 # Public interface
1803 # 1810 #
1804 1811
1805 def get_config(self): 1812 def get_config(self):
1806 """Returns the Config instance this symbol is from.""" 1813 """Returns the Config instance this symbol is from."""
1807 return self.config 1814 return self.config
1808 1815
1809 def get_name(self): 1816 def get_name(self):
1810 """Returns the name of the symbol.""" 1817 """Returns the name of the symbol."""
1811 return self.name 1818 return self.name
1812 1819
1813 def get_type(self): 1820 def get_type(self):
1814 """Returns the type of the symbol: one of UNKNOWN, BOOL, TRISTATE, 1821 """Returns the type of the symbol: one of UNKNOWN, BOOL, TRISTATE,
1815 STRING, HEX, or INT. These are defined at the top level of the module, 1822 STRING, HEX, or INT. These are defined at the top level of the module,
1816 so you'd do something like 1823 so you'd do something like
1817 1824
1818 if sym.get_type() == kconfiglib.STRING: 1825 if sym.get_type() == kconfiglib.STRING:
1819 ...""" 1826 ..."""
1820 return self.type 1827 return self.type
1821 1828
1822 def get_prompts(self): 1829 def get_prompts(self):
1823 """Returns a list of prompts defined for the symbol, in the order they 1830 """Returns a list of prompts defined for the symbol, in the order they
1824 appear in the configuration files. Returns the empty list for symbols 1831 appear in the configuration files. Returns the empty list for symbols
1825 with no prompt. 1832 with no prompt.
1826 1833
1827 This list will have a single entry for the vast majority of symbols 1834 This list will have a single entry for the vast majority of symbols
1828 having prompts, but having multiple prompts for a single symbol is 1835 having prompts, but having multiple prompts for a single symbol is
1829 possible through having multiple 'config' entries for it.""" 1836 possible through having multiple 'config' entries for it."""
1830 return [prompt for prompt, _ in self.orig_prompts] 1837 return [prompt for prompt, _ in self.orig_prompts]
1831 1838
1832 def get_help(self): 1839 def get_help(self):
1833 """Returns the help text of the symbol, or None if the symbol has no 1840 """Returns the help text of the symbol, or None if the symbol has no
1834 help text.""" 1841 help text."""
1835 return self.help 1842 return self.help
1836 1843
1837 def get_parent(self): 1844 def get_parent(self):
1838 """Returns the menu or choice statement that contains the symbol, or 1845 """Returns the menu or choice statement that contains the symbol, or
1839 None if the symbol is at the top level. Note that if statements are 1846 None if the symbol is at the top level. Note that if statements are
1840 treated as syntactic and do not have an explicit class 1847 treated as syntactic and do not have an explicit class
1841 representation.""" 1848 representation."""
1842 return self.parent 1849 return self.parent
1843 1850
1844 def get_def_locations(self): 1851 def get_def_locations(self):
1845 """Returns a list of (filename, linenr) tuples, where filename (string) 1852 """Returns a list of (filename, linenr) tuples, where filename (string)
1846 and linenr (int) represent a location where the symbol is defined. For 1853 and linenr (int) represent a location where the symbol is defined. For
1847 the vast majority of symbols this list will only contain one element. 1854 the vast majority of symbols this list will only contain one element.
1848 For the following Kconfig, FOO would get two entries: the lines marked 1855 For the following Kconfig, FOO would get two entries: the lines marked
1849 with *. 1856 with *.
1850 1857
1851 config FOO * 1858 config FOO *
1852 bool "foo prompt 1" 1859 bool "foo prompt 1"
1853 1860
1854 config FOO * 1861 config FOO *
1855 bool "foo prompt 2" 1862 bool "foo prompt 2"
1856 """ 1863 """
1857 return self.def_locations 1864 return self.def_locations
1858 1865
1859 def get_ref_locations(self): 1866 def get_ref_locations(self):
1860 """Returns a list of (filename, linenr) tuples, where filename (string) 1867 """Returns a list of (filename, linenr) tuples, where filename (string)
1861 and linenr (int) represent a location where the symbol is referenced in 1868 and linenr (int) represent a location where the symbol is referenced in
1862 the configuration. For example, the lines marked by * would be included 1869 the configuration. For example, the lines marked by * would be included
1863 for FOO below: 1870 for FOO below:
1864 1871
1865 config A 1872 config A
1866 bool 1873 bool
1867 default BAR || FOO * 1874 default BAR || FOO *
1868 1875
1869 config B 1876 config B
1870 tristate 1877 tristate
1871 depends on FOO * 1878 depends on FOO *
1872 default m if FOO * 1879 default m if FOO *
1873 1880
1874 if FOO * 1881 if FOO *
1875 config A 1882 config A
1876 bool "A" 1883 bool "A"
1877 endif 1884 endif
1878 1885
1879 config FOO (definition not included) 1886 config FOO (definition not included)
1880 bool 1887 bool
1881 """ 1888 """
1882 return self.ref_locations 1889 return self.ref_locations
1883 1890
1884 def get_value(self): 1891 def get_value(self):
1885 """Calculate and return the value of the symbol. See also 1892 """Calculate and return the value of the symbol. See also
1886 Symbol.set_user_value().""" 1893 Symbol.set_user_value()."""
1887 1894
1888 if self.cached_val is not None: 1895 if self.cached_val is not None:
1889 return self.cached_val 1896 return self.cached_val
1890 1897
1891 # As a quirk of Kconfig, undefined symbols get their name as their 1898 # As a quirk of Kconfig, undefined symbols get their name as their
1892 # value. This is why things like "FOO = bar" work for seeing if FOO has 1899 # value. This is why things like "FOO = bar" work for seeing if FOO has
1893 # the value "bar". 1900 # the value "bar".
1894 if self.type == UNKNOWN: 1901 if self.type == UNKNOWN:
1895 self.cached_val = self.name 1902 self.cached_val = self.name
1896 return self.name 1903 return self.name
1897 1904
1898 new_val = DEFAULT_VALUE[self.type] 1905 new_val = DEFAULT_VALUE[self.type]
1899 vis = _get_visibility(self) 1906 vis = _get_visibility(self)
1900 1907
1901 # This is easiest to calculate together with the value 1908 # This is easiest to calculate together with the value
1902 self.write_to_conf = False 1909 self.write_to_conf = False
1903 1910
1904 if self.type == BOOL or self.type == TRISTATE: 1911 if self.type == BOOL or self.type == TRISTATE:
1905 # The visibility and mode (modules-only or single-selection) of 1912 # The visibility and mode (modules-only or single-selection) of
1906 # choice items will be taken into account in _get_visibility() 1913 # choice items will be taken into account in _get_visibility()
1907 if self.is_choice_sym: 1914 if self.is_choice_sym:
1908 if vis != "n": 1915 if vis != "n":
1909 choice = self.parent 1916 choice = self.parent
1910 mode = choice.get_mode() 1917 mode = choice.get_mode()
1911 1918
1912 self.write_to_conf = (mode != "n") 1919 self.write_to_conf = (mode != "n")
1913 1920
1914 if mode == "y": 1921 if mode == "y":
1915 if choice.get_selection() is self: 1922 if choice.get_selection() is self:
1916 new_val = "y" 1923 new_val = "y"
1917 else: 1924 else:
1918 new_val = "n" 1925 new_val = "n"
1919 elif mode == "m": 1926 elif mode == "m":
1920 if self.user_val == "m" or self.user_val == "y": 1927 if self.user_val == "m" or self.user_val == "y":
1921 new_val = "m" 1928 new_val = "m"
1922 1929
1923 else: 1930 else:
1924 # If the symbol is visible and has a user value, use that. 1931 # If the symbol is visible and has a user value, use that.
1925 # Otherwise, look at defaults. 1932 # Otherwise, look at defaults.
1926 use_defaults = True 1933 use_defaults = True
1927 1934
1928 if vis != "n": 1935 if vis != "n":
1929 self.write_to_conf = True 1936 self.write_to_conf = True
1930 if self.user_val is not None: 1937 if self.user_val is not None:
1931 new_val = self.config._eval_min(self.user_val, vis) 1938 new_val = self.config._eval_min(self.user_val, vis)
1932 use_defaults = False 1939 use_defaults = False
1933 1940
1934 if use_defaults: 1941 if use_defaults:
1935 for val_expr, cond_expr in self.def_exprs: 1942 for val_expr, cond_expr in self.def_exprs:
1936 cond_eval = self.config._eval_expr(cond_expr) 1943 cond_eval = self.config._eval_expr(cond_expr)
1937 if cond_eval != "n": 1944 if cond_eval != "n":
1938 self.write_to_conf = True 1945 self.write_to_conf = True
1939 new_val = self.config._eval_min(val_expr, 1946 new_val = self.config._eval_min(val_expr,
1940 cond_eval) 1947 cond_eval)
1941 break 1948 break
1942 1949
1943 # Reverse (select-related) dependencies take precedence 1950 # Reverse (select-related) dependencies take precedence
1944 rev_dep_val = self.config._eval_expr(self.rev_dep) 1951 rev_dep_val = self.config._eval_expr(self.rev_dep)
1945 if rev_dep_val != "n": 1952 if rev_dep_val != "n":
1946 self.write_to_conf = True 1953 self.write_to_conf = True
1947 new_val = self.config._eval_max(new_val, rev_dep_val) 1954 new_val = self.config._eval_max(new_val, rev_dep_val)
1948 1955
1949 # Promote "m" to "y" for booleans 1956 # Promote "m" to "y" for booleans
1950 if new_val == "m" and self.type == BOOL: 1957 if new_val == "m" and self.type == BOOL:
1951 new_val = "y" 1958 new_val = "y"
1952 1959
1953 elif self.type == INT or self.type == HEX: 1960 elif self.type == INT or self.type == HEX:
1954 has_active_range = False 1961 has_active_range = False
1955 low = None 1962 low = None
1956 high = None 1963 high = None
1957 use_defaults = True 1964 use_defaults = True
1958 1965
1959 base = 16 if self.type == HEX else 10 1966 base = 16 if self.type == HEX else 10
1960 1967
1961 for l, h, cond_expr in self.ranges: 1968 for l, h, cond_expr in self.ranges:
1962 if self.config._eval_expr(cond_expr) != "n": 1969 if self.config._eval_expr(cond_expr) != "n":
1963 has_active_range = True 1970 has_active_range = True
1964 1971
1965 low_str = _str_val(l) 1972 low_str = _str_val(l)
1966 high_str = _str_val(h) 1973 high_str = _str_val(h)
1967 low = int(low_str, base) if \ 1974 low = int(low_str, base) if \
1968 _is_base_n(low_str, base) else 0 1975 _is_base_n(low_str, base) else 0
1969 high = int(high_str, base) if \ 1976 high = int(high_str, base) if \
1970 _is_base_n(high_str, base) else 0 1977 _is_base_n(high_str, base) else 0
1971 1978
1972 break 1979 break
1973 1980
1974 if vis != "n": 1981 if vis != "n":
1975 self.write_to_conf = True 1982 self.write_to_conf = True
1976 1983
1977 if self.user_val is not None and \ 1984 if self.user_val is not None and \
1978 _is_base_n(self.user_val, base) and \ 1985 _is_base_n(self.user_val, base) and \
1979 (not has_active_range or 1986 (not has_active_range or
1980 low <= int(self.user_val, base) <= high): 1987 low <= int(self.user_val, base) <= high):
1981 1988
1982 # If the user value is OK, it is stored in exactly the same 1989 # If the user value is OK, it is stored in exactly the same
1983 # form as specified in the assignment (with or without 1990 # form as specified in the assignment (with or without
1984 # "0x", etc). 1991 # "0x", etc).
1985 1992
1986 use_defaults = False 1993 use_defaults = False
1987 new_val = self.user_val 1994 new_val = self.user_val
1988 1995
1989 if use_defaults: 1996 if use_defaults:
1990 for val_expr, cond_expr in self.def_exprs: 1997 for val_expr, cond_expr in self.def_exprs:
1991 if self.config._eval_expr(cond_expr) != "n": 1998 if self.config._eval_expr(cond_expr) != "n":
1992 self.write_to_conf = True 1999 self.write_to_conf = True
1993 2000
1994 # If the default value is OK, it is stored in exactly 2001 # If the default value is OK, it is stored in exactly
1995 # the same form as specified. Otherwise, it is clamped 2002 # the same form as specified. Otherwise, it is clamped
1996 # to the range, and the output has "0x" as appropriate 2003 # to the range, and the output has "0x" as appropriate
1997 # for the type. 2004 # for the type.
1998 2005
1999 new_val = _str_val(val_expr) 2006 new_val = _str_val(val_expr)
2000 2007
2001 if _is_base_n(new_val, base): 2008 if _is_base_n(new_val, base):
2002 new_val_num = int(new_val, base) 2009 new_val_num = int(new_val, base)
2003 if has_active_range: 2010 if has_active_range:
2004 clamped_val = None 2011 clamped_val = None
2005 2012
2006 if new_val_num < low: 2013 if new_val_num < low:
2007 clamped_val = low 2014 clamped_val = low
2008 elif new_val_num > high: 2015 elif new_val_num > high:
2009 clamped_val = high 2016 clamped_val = high
2010 2017
2011 if clamped_val is not None: 2018 if clamped_val is not None:
2012 new_val = (hex(clamped_val) if \ 2019 new_val = (hex(clamped_val) if \
2013 self.type == HEX else str(clamped_val)) 2020 self.type == HEX else str(clamped_val))
2014 2021
2015 break 2022 break
2016 else: # For the for loop 2023 else: # For the for loop
2017 # If no user value or default kicks in but the hex/int has 2024 # If no user value or default kicks in but the hex/int has
2018 # an active range, then the low end of the range is used, 2025 # an active range, then the low end of the range is used,
2019 # provided it's > 0, with "0x" prepended as appropriate. 2026 # provided it's > 0, with "0x" prepended as appropriate.
2020 if has_active_range and low > 0: 2027 if has_active_range and low > 0:
2021 new_val = (hex(low) if self.type == HEX else str(low)) 2028 new_val = (hex(low) if self.type == HEX else str(low))
2022 2029
2023 elif self.type == STRING: 2030 elif self.type == STRING:
2024 use_defaults = True 2031 use_defaults = True
2025 2032
2026 if vis != "n": 2033 if vis != "n":
2027 self.write_to_conf = True 2034 self.write_to_conf = True
2028 if self.user_val is not None: 2035 if self.user_val is not None:
2029 new_val = self.user_val 2036 new_val = self.user_val
2030 use_defaults = False 2037 use_defaults = False
2031 2038
2032 if use_defaults: 2039 if use_defaults:
2033 for val_expr, cond_expr in self.def_exprs: 2040 for val_expr, cond_expr in self.def_exprs:
2034 if self.config._eval_expr(cond_expr) != "n": 2041 if self.config._eval_expr(cond_expr) != "n":
2035 self.write_to_conf = True 2042 self.write_to_conf = True
2036 new_val = _str_val(val_expr) 2043 new_val = _str_val(val_expr)
2037 break 2044 break
2038 2045
2039 self.cached_val = new_val 2046 self.cached_val = new_val
2040 return new_val 2047 return new_val
2041 2048
2042 def get_user_value(self): 2049 def get_user_value(self):
2043 """Returns the value assigned to the symbol in a .config or via 2050 """Returns the value assigned to the symbol in a .config or via
2044 Symbol.set_user_value() (provided the value was valid for the type of 2051 Symbol.set_user_value() (provided the value was valid for the type of
2045 the symbol). Returns None in case of no user value.""" 2052 the symbol). Returns None in case of no user value."""
2046 return self.user_val 2053 return self.user_val
2047 2054
2048 def get_upper_bound(self): 2055 def get_upper_bound(self):
2049 """For string/hex/int symbols and for bool and tristate symbols that 2056 """For string/hex/int symbols and for bool and tristate symbols that
2050 cannot be modified (see is_modifiable()), returns None. 2057 cannot be modified (see is_modifiable()), returns None.
2051 2058
2052 Otherwise, returns the highest value the symbol can be set to with 2059 Otherwise, returns the highest value the symbol can be set to with
2053 Symbol.set_user_value() (that will not be truncated): one of "m" or 2060 Symbol.set_user_value() (that will not be truncated): one of "m" or
2054 "y", arranged from lowest to highest. This corresponds to the highest 2061 "y", arranged from lowest to highest. This corresponds to the highest
2055 value the symbol could be given in e.g. the 'make menuconfig' 2062 value the symbol could be given in e.g. the 'make menuconfig'
2056 interface. 2063 interface.
2057 2064
2058 See also the tri_less*() and tri_greater*() functions, which could come 2065 See also the tri_less*() and tri_greater*() functions, which could come
2059 in handy.""" 2066 in handy."""
2060 if self.type != BOOL and self.type != TRISTATE: 2067 if self.type != BOOL and self.type != TRISTATE:
2061 return None 2068 return None
2062 rev_dep = self.config._eval_expr(self.rev_dep) 2069 rev_dep = self.config._eval_expr(self.rev_dep)
2063 # A bool selected to "m" gets promoted to "y", pinning it 2070 # A bool selected to "m" gets promoted to "y", pinning it
2064 if rev_dep == "m" and self.type == BOOL: 2071 if rev_dep == "m" and self.type == BOOL:
2065 return None 2072 return None
2066 vis = _get_visibility(self) 2073 vis = _get_visibility(self)
2067 if TRI_TO_INT[vis] > TRI_TO_INT[rev_dep]: 2074 if TRI_TO_INT[vis] > TRI_TO_INT[rev_dep]:
2068 return vis 2075 return vis
2069 return None 2076 return None
2070 2077
2071 def get_lower_bound(self): 2078 def get_lower_bound(self):
2072 """For string/hex/int symbols and for bool and tristate symbols that 2079 """For string/hex/int symbols and for bool and tristate symbols that
2073 cannot be modified (see is_modifiable()), returns None. 2080 cannot be modified (see is_modifiable()), returns None.
2074 2081
2075 Otherwise, returns the lowest value the symbol can be set to with 2082 Otherwise, returns the lowest value the symbol can be set to with
2076 Symbol.set_user_value() (that will not be truncated): one of "n" or 2083 Symbol.set_user_value() (that will not be truncated): one of "n" or
2077 "m", arranged from lowest to highest. This corresponds to the lowest 2084 "m", arranged from lowest to highest. This corresponds to the lowest
2078 value the symbol could be given in e.g. the 'make menuconfig' 2085 value the symbol could be given in e.g. the 'make menuconfig'
2079 interface. 2086 interface.
2080 2087
2081 See also the tri_less*() and tri_greater*() functions, which could come 2088 See also the tri_less*() and tri_greater*() functions, which could come
2082 in handy.""" 2089 in handy."""
2083 if self.type != BOOL and self.type != TRISTATE: 2090 if self.type != BOOL and self.type != TRISTATE:
2084 return None 2091 return None
2085 rev_dep = self.config._eval_expr(self.rev_dep) 2092 rev_dep = self.config._eval_expr(self.rev_dep)
2086 # A bool selected to "m" gets promoted to "y", pinning it 2093 # A bool selected to "m" gets promoted to "y", pinning it
2087 if rev_dep == "m" and self.type == BOOL: 2094 if rev_dep == "m" and self.type == BOOL:
2088 return None 2095 return None
2089 if TRI_TO_INT[_get_visibility(self)] > TRI_TO_INT[rev_dep]: 2096 if TRI_TO_INT[_get_visibility(self)] > TRI_TO_INT[rev_dep]:
2090 return rev_dep 2097 return rev_dep
2091 return None 2098 return None
2092 2099
2093 def get_assignable_values(self): 2100 def get_assignable_values(self):
2094 """For string/hex/int symbols and for bool and tristate symbols that 2101 """For string/hex/int symbols and for bool and tristate symbols that
2095 cannot be modified (see is_modifiable()), returns the empty list. 2102 cannot be modified (see is_modifiable()), returns the empty list.
2096 2103
2097 Otherwise, returns a list containing the user values that can be 2104 Otherwise, returns a list containing the user values that can be
2098 assigned to the symbol (that won't be truncated). Usage example: 2105 assigned to the symbol (that won't be truncated). Usage example:
2099 2106
2100 if "m" in sym.get_assignable_values(): 2107 if "m" in sym.get_assignable_values():
2101 sym.set_user_value("m") 2108 sym.set_user_value("m")
2102 2109
2103 This is basically a more convenient interface to 2110 This is basically a more convenient interface to
2104 get_lower/upper_bound() when wanting to test if a particular tristate 2111 get_lower/upper_bound() when wanting to test if a particular tristate
2105 value can be assigned.""" 2112 value can be assigned."""
2106 if self.type != BOOL and self.type != TRISTATE: 2113 if self.type != BOOL and self.type != TRISTATE:
2107 return [] 2114 return []
2108 rev_dep = self.config._eval_expr(self.rev_dep) 2115 rev_dep = self.config._eval_expr(self.rev_dep)
2109 # A bool selected to "m" gets promoted to "y", pinning it 2116 # A bool selected to "m" gets promoted to "y", pinning it
2110 if rev_dep == "m" and self.type == BOOL: 2117 if rev_dep == "m" and self.type == BOOL:
2111 return [] 2118 return []
2112 res = ["n", "m", "y"][TRI_TO_INT[rev_dep] : 2119 res = ["n", "m", "y"][TRI_TO_INT[rev_dep] :
2113 TRI_TO_INT[_get_visibility(self)] + 1] 2120 TRI_TO_INT[_get_visibility(self)] + 1]
2114 return res if len(res) > 1 else [] 2121 return res if len(res) > 1 else []
2115 2122
2116 def get_visibility(self): 2123 def get_visibility(self):
2117 """Returns the visibility of the symbol: one of "n", "m" or "y". For 2124 """Returns the visibility of the symbol: one of "n", "m" or "y". For
2118 bool and tristate symbols, this is an upper bound on the value users 2125 bool and tristate symbols, this is an upper bound on the value users
2119 can set for the symbol. For other types of symbols, a visibility of "n" 2126 can set for the symbol. For other types of symbols, a visibility of "n"
2120 means the user value will be ignored. A visibility of "n" corresponds 2127 means the user value will be ignored. A visibility of "n" corresponds
2121 to not being visible in the 'make *config' interfaces. 2128 to not being visible in the 'make *config' interfaces.
2122 2129
2123 Example (assuming we're running with modules enabled -- i.e., MODULES 2130 Example (assuming we're running with modules enabled -- i.e., MODULES
2124 set to 'y'): 2131 set to 'y'):
2125 2132
2126 # Assume this has been assigned 'n' 2133 # Assume this has been assigned 'n'
2127 config N_SYM 2134 config N_SYM
2128 tristate "N_SYM" 2135 tristate "N_SYM"
2129 2136
2130 # Assume this has been assigned 'm' 2137 # Assume this has been assigned 'm'
2131 config M_SYM 2138 config M_SYM
2132 tristate "M_SYM" 2139 tristate "M_SYM"
2133 2140
2134 # Has visibility 'n' 2141 # Has visibility 'n'
2135 config A 2142 config A
2136 tristate "A" 2143 tristate "A"
2137 depends on N_SYM 2144 depends on N_SYM
2138 2145
2139 # Has visibility 'm' 2146 # Has visibility 'm'
2140 config B 2147 config B
2141 tristate "B" 2148 tristate "B"
2142 depends on M_SYM 2149 depends on M_SYM
2143 2150
2144 # Has visibility 'y' 2151 # Has visibility 'y'
2145 config C 2152 config C
2146 tristate "C" 2153 tristate "C"
2147 2154
2148 # Has no prompt, and hence visibility 'n' 2155 # Has no prompt, and hence visibility 'n'
2149 config D 2156 config D
2150 tristate 2157 tristate
2151 2158
2152 Having visibility be tri-valued ensures that e.g. a symbol cannot be 2159 Having visibility be tri-valued ensures that e.g. a symbol cannot be
2153 set to "y" by the user if it depends on a symbol with value "m", which 2160 set to "y" by the user if it depends on a symbol with value "m", which
2154 wouldn't be safe. 2161 wouldn't be safe.
2155 2162
2156 You should probably look at get_lower/upper_bound(), 2163 You should probably look at get_lower/upper_bound(),
2157 get_assignable_values() and is_modifiable() before using this.""" 2164 get_assignable_values() and is_modifiable() before using this."""
2158 return _get_visibility(self) 2165 return _get_visibility(self)
2159 2166
2160 def get_referenced_symbols(self, refs_from_enclosing=False): 2167 def get_referenced_symbols(self, refs_from_enclosing=False):
2161 """Returns the set() of all symbols referenced by this symbol. For 2168 """Returns the set() of all symbols referenced by this symbol. For
2162 example, the symbol defined by 2169 example, the symbol defined by
2163 2170
2164 config FOO 2171 config FOO
2165 bool 2172 bool
2166 prompt "foo" if A && B 2173 prompt "foo" if A && B
2167 default C if D 2174 default C if D
2168 depends on E 2175 depends on E
2169 select F if G 2176 select F if G
2170 2177
2171 references the symbols A through G. 2178 references the symbols A through G.
2172 2179
2173 refs_from_enclosing (default: False): If True, the symbols referenced 2180 refs_from_enclosing (default: False): If True, the symbols referenced
2174 by enclosing menus and ifs will be included in the result.""" 2181 by enclosing menus and ifs will be included in the result."""
2175 return self.all_referenced_syms if refs_from_enclosing else \ 2182 return self.all_referenced_syms if refs_from_enclosing else \
2176 self.referenced_syms 2183 self.referenced_syms
2177 2184
2178 def get_selected_symbols(self): 2185 def get_selected_symbols(self):
2179 """Returns the set() of all symbols X for which this symbol has a 2186 """Returns the set() of all symbols X for which this symbol has a
2180 'select X' or 'select X if Y' (regardless of whether Y is satisfied or 2187 'select X' or 'select X if Y' (regardless of whether Y is satisfied or
2181 not). This is a subset of the symbols returned by 2188 not). This is a subset of the symbols returned by
2182 get_referenced_symbols().""" 2189 get_referenced_symbols()."""
2183 return self.selected_syms 2190 return self.selected_syms
2184 2191
2185 def set_user_value(self, v): 2192 def set_user_value(self, v):
2186 """Sets the user value of the symbol. 2193 """Sets the user value of the symbol.
2187 2194
2188 Equal in effect to assigning the value to the symbol within a .config 2195 Equal in effect to assigning the value to the symbol within a .config
2189 file. Use get_lower/upper_bound() or get_assignable_values() to find 2196 file. Use get_lower/upper_bound() or get_assignable_values() to find
2190 the range of currently assignable values for bool and tristate symbols; 2197 the range of currently assignable values for bool and tristate symbols;
2191 setting values outside this range will cause the user value to differ 2198 setting values outside this range will cause the user value to differ
2192 from the result of Symbol.get_value() (be truncated). Values that are 2199 from the result of Symbol.get_value() (be truncated). Values that are
2193 invalid for the type (such as a_bool.set_user_value("foo")) are 2200 invalid for the type (such as a_bool.set_user_value("foo")) are
2194 ignored, and a warning is emitted if an attempt is made to assign such 2201 ignored, and a warning is emitted if an attempt is made to assign such
2195 a value. 2202 a value.
2196 2203
2197 For any type of symbol, is_modifiable() can be used to check if a user 2204 For any type of symbol, is_modifiable() can be used to check if a user
2198 value will currently have any effect on the symbol, as determined by 2205 value will currently have any effect on the symbol, as determined by
2199 its visibility and range of assignable values. Any value that is valid 2206 its visibility and range of assignable values. Any value that is valid
2200 for the type (bool, tristate, etc.) will end up being reflected in 2207 for the type (bool, tristate, etc.) will end up being reflected in
2201 get_user_value() though, and might have an effect later if conditions 2208 get_user_value() though, and might have an effect later if conditions
2202 change. To get rid of the user value, use unset_user_value(). 2209 change. To get rid of the user value, use unset_user_value().
2203 2210
2204 Any symbols dependent on the symbol are (recursively) invalidated, so 2211 Any symbols dependent on the symbol are (recursively) invalidated, so
2205 things will just work with regards to dependencies. 2212 things will just work with regards to dependencies.
2206 2213
2207 v: The user value to give to the symbol.""" 2214 v: The user value to give to the symbol."""
2208 self._set_user_value_no_invalidate(v, False) 2215 self._set_user_value_no_invalidate(v, False)
2209 2216
2210 # There might be something more efficient you could do here, but play 2217 # There might be something more efficient you could do here, but play
2211 # it safe. 2218 # it safe.
2212 if self.name == "MODULES": 2219 if self.name == "MODULES":
2213 self.config._invalidate_all() 2220 self.config._invalidate_all()
2214 return 2221 return
2215 2222
2216 self._invalidate() 2223 self._invalidate()
2217 self._invalidate_dependent() 2224 self._invalidate_dependent()
2218 2225
2219 def unset_user_value(self): 2226 def unset_user_value(self):
2220 """Resets the user value of the symbol, as if the symbol had never 2227 """Resets the user value of the symbol, as if the symbol had never
2221 gotten a user value via Config.load_config() or 2228 gotten a user value via Config.load_config() or
2222 Symbol.set_user_value().""" 2229 Symbol.set_user_value()."""
2223 self._unset_user_value_no_recursive_invalidate() 2230 self._unset_user_value_no_recursive_invalidate()
2224 self._invalidate_dependent() 2231 self._invalidate_dependent()
2225 2232
2226 def is_modifiable(self): 2233 def is_modifiable(self):
2227 """Returns True if the value of the symbol could be modified by calling 2234 """Returns True if the value of the symbol could be modified by calling
2228 Symbol.set_user_value(). 2235 Symbol.set_user_value().
2229 2236
2230 For bools and tristates, this corresponds to the symbol being visible 2237 For bools and tristates, this corresponds to the symbol being visible
2231 in the 'make menuconfig' interface and not already being pinned to a 2238 in the 'make menuconfig' interface and not already being pinned to a
2232 specific value (e.g. because it is selected by another symbol). 2239 specific value (e.g. because it is selected by another symbol).
2233 2240
2234 For strings and numbers, this corresponds to just being visible. (See 2241 For strings and numbers, this corresponds to just being visible. (See
2235 Symbol.get_visibility().)""" 2242 Symbol.get_visibility().)"""
2236 if self.is_special_: 2243 if self.is_special_:
2237 return False 2244 return False
2238 if self.type == BOOL or self.type == TRISTATE: 2245 if self.type == BOOL or self.type == TRISTATE:
2239 rev_dep = self.config._eval_expr(self.rev_dep) 2246 rev_dep = self.config._eval_expr(self.rev_dep)
2240 # A bool selected to "m" gets promoted to "y", pinning it 2247 # A bool selected to "m" gets promoted to "y", pinning it
2241 if rev_dep == "m" and self.type == BOOL: 2248 if rev_dep == "m" and self.type == BOOL:
2242 return False 2249 return False
2243 return TRI_TO_INT[_get_visibility(self)] > TRI_TO_INT[rev_dep] 2250 return TRI_TO_INT[_get_visibility(self)] > TRI_TO_INT[rev_dep]
2244 return _get_visibility(self) != "n" 2251 return _get_visibility(self) != "n"
2245 2252
2246 def is_defined(self): 2253 def is_defined(self):
2247 """Returns False if the symbol is referred to in the Kconfig but never 2254 """Returns False if the symbol is referred to in the Kconfig but never
2248 actually defined.""" 2255 actually defined."""
2249 return self.is_defined_ 2256 return self.is_defined_
2250 2257
2251 def is_special(self): 2258 def is_special(self):
2252 """Returns True if the symbol is one of the special symbols n, m, y, or 2259 """Returns True if the symbol is one of the special symbols n, m, y, or
2253 UNAME_RELEASE, or gets its value from the environment.""" 2260 UNAME_RELEASE, or gets its value from the environment."""
2254 return self.is_special_ 2261 return self.is_special_
2255 2262
2256 def is_from_environment(self): 2263 def is_from_environment(self):
2257 """Returns True if the symbol gets its value from the environment.""" 2264 """Returns True if the symbol gets its value from the environment."""
2258 return self.is_from_env 2265 return self.is_from_env
2259 2266
2260 def has_ranges(self): 2267 def has_ranges(self):
2261 """Returns True if the symbol is of type INT or HEX and has ranges that 2268 """Returns True if the symbol is of type INT or HEX and has ranges that
2262 limit what values it can take on.""" 2269 limit what values it can take on."""
2263 return bool(self.ranges) 2270 return bool(self.ranges)
2264 2271
2265 def is_choice_symbol(self): 2272 def is_choice_symbol(self):
2266 """Returns True if the symbol is in a choice statement and is an actual 2273 """Returns True if the symbol is in a choice statement and is an actual
2267 choice symbol (see Choice.get_symbols()).""" 2274 choice symbol (see Choice.get_symbols())."""
2268 return self.is_choice_sym 2275 return self.is_choice_sym
2269 2276
2270 def is_choice_selection(self): 2277 def is_choice_selection(self):
2271 """Returns True if the symbol is contained in a choice statement and is 2278 """Returns True if the symbol is contained in a choice statement and is
2272 the selected item. Equivalent to 2279 the selected item. Equivalent to
2273 2280
2274 sym.is_choice_symbol() and sym.get_parent().get_selection() is sym""" 2281 sym.is_choice_symbol() and sym.get_parent().get_selection() is sym"""
2275 return self.is_choice_sym and self.parent.get_selection() is self 2282 return self.is_choice_sym and self.parent.get_selection() is self
2276 2283
2277 def is_allnoconfig_y(self): 2284 def is_allnoconfig_y(self):
2278 """Returns True if the symbol has the 'allnoconfig_y' option set.""" 2285 """Returns True if the symbol has the 'allnoconfig_y' option set."""
2279 return self.allnoconfig_y 2286 return self.allnoconfig_y
2280 2287
2281 def __str__(self): 2288 def __str__(self):
2282 """Returns a string containing various information about the symbol.""" 2289 """Returns a string containing various information about the symbol."""
2283 return self.config._get_sym_or_choice_str(self) 2290 return self.config._get_sym_or_choice_str(self)
2284 2291
2285 # 2292 #
2286 # Private methods 2293 # Private methods
2287 # 2294 #
2288 2295
2289 def __init__(self): 2296 def __init__(self):
2290 """Symbol constructor -- not intended to be called directly by 2297 """Symbol constructor -- not intended to be called directly by
2291 Kconfiglib clients.""" 2298 Kconfiglib clients."""
2292 2299
2293 self.name = None 2300 self.name = None
2294 self.type = UNKNOWN 2301 self.type = UNKNOWN
2295 self.prompts = [] 2302 self.prompts = []
2296 self.def_exprs = [] # 'default' properties 2303 self.def_exprs = [] # 'default' properties
2297 self.ranges = [] # 'range' properties (for int and hex) 2304 self.ranges = [] # 'range' properties (for int and hex)
2298 self.help = None # Help text 2305 self.help = None # Help text
2299 self.rev_dep = "n" # Reverse (select-related) dependencies 2306 self.rev_dep = "n" # Reverse (select-related) dependencies
2300 self.config = None 2307 self.config = None
2301 self.parent = None 2308 self.parent = None
2302 2309
2303 self.user_val = None # Value set by user 2310 self.user_val = None # Value set by user
2304 2311
2305 # The prompt, default value and select conditions without any 2312 # The prompt, default value and select conditions without any
2306 # dependencies from menus and ifs propagated to them 2313 # dependencies from menus and ifs propagated to them
2307 self.orig_prompts = [] 2314 self.orig_prompts = []
2308 self.orig_def_exprs = [] 2315 self.orig_def_exprs = []
2309 self.orig_selects = [] 2316 self.orig_selects = []
2310 2317
2311 # Dependencies inherited from containing menus and ifs 2318 # Dependencies inherited from containing menus and ifs
2312 self.deps_from_containing = None 2319 self.deps_from_containing = None
2313 # The set of symbols referenced by this symbol (see 2320 # The set of symbols referenced by this symbol (see
2314 # get_referenced_symbols()) 2321 # get_referenced_symbols())
2315 self.referenced_syms = set() 2322 self.referenced_syms = set()
2316 # The set of symbols selected by this symbol (see 2323 # The set of symbols selected by this symbol (see
2317 # get_selected_symbols()) 2324 # get_selected_symbols())
2318 self.selected_syms = set() 2325 self.selected_syms = set()
2319 # Like 'referenced_syms', but includes symbols from 2326 # Like 'referenced_syms', but includes symbols from
2320 # dependencies inherited from enclosing menus and ifs 2327 # dependencies inherited from enclosing menus and ifs
2321 self.all_referenced_syms = set() 2328 self.all_referenced_syms = set()
2322 2329
2323 # This records only dependencies specified with 'depends on'. Needed 2330 # This records only dependencies specified with 'depends on'. Needed
2324 # when determining actual choice items (hrrrr...). See also 2331 # when determining actual choice items (hrrrr...). See also
2325 # Choice._determine_actual_symbols(). 2332 # Choice._determine_actual_symbols().
2326 self.menu_dep = None 2333 self.menu_dep = None
2327 2334
2328 # See Symbol.get_ref/def_locations(). 2335 # See Symbol.get_ref/def_locations().
2329 self.def_locations = [] 2336 self.def_locations = []
2330 self.ref_locations = [] 2337 self.ref_locations = []
2331 2338
2332 # Populated in Config._build_dep() after parsing. Links the symbol to 2339 # Populated in Config._build_dep() after parsing. Links the symbol to
2333 # the symbols that immediately depend on it (in a caching/invalidation 2340 # the symbols that immediately depend on it (in a caching/invalidation
2334 # sense). The total set of dependent symbols for the symbol (the 2341 # sense). The total set of dependent symbols for the symbol (the
2335 # transitive closure) is calculated on an as-needed basis in 2342 # transitive closure) is calculated on an as-needed basis in
2336 # _get_dependent(). 2343 # _get_dependent().
2337 self.dep = set() 2344 self.dep = set()
2338 2345
2339 # Cached values 2346 # Cached values
2340 2347
2341 # Caches the calculated value 2348 # Caches the calculated value
2342 self.cached_val = None 2349 self.cached_val = None
2343 # Caches the visibility, which acts as an upper bound on the value 2350 # Caches the visibility, which acts as an upper bound on the value
2344 self.cached_visibility = None 2351 self.cached_visibility = None
2345 # Caches the total list of dependent symbols. Calculated in 2352 # Caches the total list of dependent symbols. Calculated in
2346 # _get_dependent(). 2353 # _get_dependent().
2347 self.cached_deps = None 2354 self.cached_deps = None
2348 2355
2349 # Flags 2356 # Flags
2350 2357
2351 # Does the symbol have an entry in the Kconfig file? The trailing 2358 # Does the symbol have an entry in the Kconfig file? The trailing
2352 # underscore avoids a collision with is_defined(). 2359 # underscore avoids a collision with is_defined().
2353 self.is_defined_ = False 2360 self.is_defined_ = False
2354 # Should the symbol get an entry in .config? 2361 # Should the symbol get an entry in .config?
2355 self.write_to_conf = False 2362 self.write_to_conf = False
2356 # Set to true when _make_conf() is called on a symbol, so that symbols 2363 # Set to true when _make_conf() is called on a symbol, so that symbols
2357 # defined in multiple locations only get one .config entry. We need to 2364 # defined in multiple locations only get one .config entry. We need to
2358 # reset it prior to writing out a new .config. 2365 # reset it prior to writing out a new .config.
2359 self.already_written = False 2366 self.already_written = False
2360 # This is set to True for "actual" choice symbols; see 2367 # This is set to True for "actual" choice symbols; see
2361 # Choice._determine_actual_symbols(). 2368 # Choice._determine_actual_symbols().
2362 self.is_choice_sym = False 2369 self.is_choice_sym = False
2363 # Does the symbol get its value in some special way, e.g. from the 2370 # Does the symbol get its value in some special way, e.g. from the
2364 # environment or by being one of the special symbols n, m, and y? If 2371 # environment or by being one of the special symbols n, m, and y? If
2365 # so, the value is stored in self.cached_val, which is never 2372 # so, the value is stored in self.cached_val, which is never
2366 # invalidated. The trailing underscore avoids a collision with 2373 # invalidated. The trailing underscore avoids a collision with
2367 # is_special(). 2374 # is_special().
2368 self.is_special_ = False 2375 self.is_special_ = False
2369 # Does the symbol get its value from the environment? 2376 # Does the symbol get its value from the environment?
2370 self.is_from_env = False 2377 self.is_from_env = False
2371 # Does the symbol have the 'allnoconfig_y' option set? 2378 # Does the symbol have the 'allnoconfig_y' option set?
2372 self.allnoconfig_y = False 2379 self.allnoconfig_y = False
2373 2380
2374 def _invalidate(self): 2381 def _invalidate(self):
2375 if self.is_special_: 2382 if self.is_special_:
2376 return 2383 return
2377 2384
2378 if self.is_choice_sym: 2385 if self.is_choice_sym:
2379 self.parent._invalidate() 2386 self.parent._invalidate()
2380 2387
2381 self.cached_val = None 2388 self.cached_val = None
2382 self.cached_visibility = None 2389 self.cached_visibility = None
2383 2390
2384 def _invalidate_dependent(self): 2391 def _invalidate_dependent(self):
2385 for sym in self._get_dependent(): 2392 for sym in self._get_dependent():
2386 sym._invalidate() 2393 sym._invalidate()
2387 2394
2388 def _set_user_value_no_invalidate(self, v, suppress_load_warnings): 2395 def _set_user_value_no_invalidate(self, v, suppress_load_warnings):
2389 """Like set_user_value(), but does not invalidate any symbols. 2396 """Like set_user_value(), but does not invalidate any symbols.
2390 2397
2391 suppress_load_warnings: some warnings are annoying when loading a 2398 suppress_load_warnings: some warnings are annoying when loading a
2392 .config that can be helpful when manually invoking set_user_value(). 2399 .config that can be helpful when manually invoking set_user_value().
2393 This flag is set to True to suppress such warnings. 2400 This flag is set to True to suppress such warnings.
2394 2401
2395 Perhaps this could be made optional for load_config() instead.""" 2402 Perhaps this could be made optional for load_config() instead."""
2396 2403
2397 if self.is_special_: 2404 if self.is_special_:
2398 if self.is_from_env: 2405 if self.is_from_env:
2399 self.config._warn('attempt to assign the value "{0}" to the ' 2406 self.config._warn('attempt to assign the value "{0}" to the '
2400 'symbol {1}, which gets its value from the ' 2407 'symbol {1}, which gets its value from the '
2401 'environment. Assignment ignored.' 2408 'environment. Assignment ignored.'
2402 .format(v, self.name)) 2409 .format(v, self.name))
2403 else: 2410 else:
2404 self.config._warn('attempt to assign the value "{0}" to the ' 2411 self.config._warn('attempt to assign the value "{0}" to the '
2405 'special symbol {1}. Assignment ignored.' 2412 'special symbol {1}. Assignment ignored.'
2406 .format(v, self.name)) 2413 .format(v, self.name))
2407 return 2414 return
2408 2415
2409 if not self.is_defined_: 2416 if not self.is_defined_:
2410 filename, linenr = self.ref_locations[0] 2417 filename, linenr = self.ref_locations[0]
2411 if self.config.print_undef_assign: 2418 if self.config.print_undef_assign:
2412 _stderr_msg('note: attempt to assign the value "{0}" to {1}, ' 2419 _stderr_msg('note: attempt to assign the value "{0}" to {1}, '
2413 "which is referenced at {2}:{3} but never " 2420 "which is referenced at {2}:{3} but never "
2414 "defined. Assignment ignored." 2421 "defined. Assignment ignored."
2415 .format(v, self.name, filename, linenr)) 2422 .format(v, self.name, filename, linenr))
2416 return 2423 return
2417 2424
2418 # Check if the value is valid for our type 2425 # Check if the value is valid for our type
2419 if not ((self.type == BOOL and (v == "y" or v == "n") ) or 2426 if not ((self.type == BOOL and (v == "y" or v == "n") ) or
2420 (self.type == TRISTATE and (v == "y" or v == "m" or 2427 (self.type == TRISTATE and (v == "y" or v == "m" or
2421 v == "n") ) or 2428 v == "n") ) or
2422 (self.type == STRING ) or 2429 (self.type == STRING ) or
2423 (self.type == INT and _is_base_n(v, 10) ) or 2430 (self.type == INT and _is_base_n(v, 10) ) or
2424 (self.type == HEX and _is_base_n(v, 16) )): 2431 (self.type == HEX and _is_base_n(v, 16) )):
2425 self.config._warn('the value "{0}" is invalid for {1}, which has ' 2432 self.config._warn('the value "{0}" is invalid for {1}, which has '
2426 "type {2}. Assignment ignored." 2433 "type {2}. Assignment ignored."
2427 .format(v, self.name, TYPENAME[self.type])) 2434 .format(v, self.name, TYPENAME[self.type]))
2428 return 2435 return
2429 2436
2430 if not self.prompts and not suppress_load_warnings: 2437 if not self.prompts and not suppress_load_warnings:
2431 self.config._warn('assigning "{0}" to the symbol {1} which ' 2438 self.config._warn('assigning "{0}" to the symbol {1} which '
2432 'lacks prompts and thus has visibility "n". ' 2439 'lacks prompts and thus has visibility "n". '
2433 'The assignment will have no effect.' 2440 'The assignment will have no effect.'
2434 .format(v, self.name)) 2441 .format(v, self.name))
2435 2442
2436 self.user_val = v 2443 self.user_val = v
2437 2444
2438 if self.is_choice_sym and (self.type == BOOL or self.type == TRISTATE): 2445 if self.is_choice_sym and (self.type == BOOL or self.type == TRISTATE):
2439 choice = self.parent 2446 choice = self.parent
2440 if v == "y": 2447 if v == "y":
2441 choice.user_val = self 2448 choice.user_val = self
2442 choice.user_mode = "y" 2449 choice.user_mode = "y"
2443 elif v == "m": 2450 elif v == "m":
2444 choice.user_val = None 2451 choice.user_val = None
2445 choice.user_mode = "m" 2452 choice.user_mode = "m"
2446 2453
2447 def _unset_user_value_no_recursive_invalidate(self): 2454 def _unset_user_value_no_recursive_invalidate(self):
2448 self._invalidate() 2455 self._invalidate()
2449 self.user_val = None 2456 self.user_val = None
2450 2457
2451 if self.is_choice_sym: 2458 if self.is_choice_sym:
2452 self.parent._unset_user_value() 2459 self.parent._unset_user_value()
2453 2460
2454 def _make_conf(self, append_fn): 2461 def _make_conf(self, append_fn):
2455 if self.already_written: 2462 if self.already_written:
2456 return 2463 return
2457 2464
2458 self.already_written = True 2465 self.already_written = True
2459 2466
2460 # Note: write_to_conf is determined in get_value() 2467 # Note: write_to_conf is determined in get_value()
2461 val = self.get_value() 2468 val = self.get_value()
2462 if not self.write_to_conf: 2469 if not self.write_to_conf:
2463 return 2470 return
2464 2471
2465 if self.type == BOOL or self.type == TRISTATE: 2472 if self.type == BOOL or self.type == TRISTATE:
2466 if val == "y" or val == "m": 2473 if val == "y" or val == "m":
2467 append_fn("CONFIG_{0}={1}".format(self.name, val)) 2474 append_fn("CONFIG_{0}={1}".format(self.name, val))
2468 else: 2475 else:
2469 append_fn("# CONFIG_{0} is not set".format(self.name)) 2476 append_fn("# CONFIG_{0} is not set".format(self.name))
2470 2477
2471 elif self.type == INT or self.type == HEX: 2478 elif self.type == INT or self.type == HEX:
2472 append_fn("CONFIG_{0}={1}".format(self.name, val)) 2479 append_fn("CONFIG_{0}={1}".format(self.name, val))
2473 2480
2474 elif self.type == STRING: 2481 elif self.type == STRING:
2475 # Escape \ and " 2482 # Escape \ and "
2476 append_fn('CONFIG_{0}="{1}"' 2483 append_fn('CONFIG_{0}="{1}"'
2477 .format(self.name, 2484 .format(self.name,
2478 val.replace("\\", "\\\\").replace('"', '\\"'))) 2485 val.replace("\\", "\\\\").replace('"', '\\"')))
2479 2486
2480 else: 2487 else:
2481 _internal_error("Internal error while creating .config: unknown " 2488 _internal_error("Internal error while creating .config: unknown "
2482 'type "{0}".'.format(self.type)) 2489 'type "{0}".'.format(self.type))
2483 2490
2484 def _get_dependent(self): 2491 def _get_dependent(self):
2485 """Returns the set of symbols that should be invalidated if the value 2492 """Returns the set of symbols that should be invalidated if the value
2486 of the symbol changes, because they might be affected by the change. 2493 of the symbol changes, because they might be affected by the change.
2487 Note that this is an internal API -- it's probably of limited 2494 Note that this is an internal API -- it's probably of limited
2488 usefulness to clients.""" 2495 usefulness to clients."""
2489 if self.cached_deps is not None: 2496 if self.cached_deps is not None:
2490 return self.cached_deps 2497 return self.cached_deps
2491 2498
2492 res = set(self.dep) 2499 res = set(self.dep)
2493 for s in self.dep: 2500 for s in self.dep:
2494 res |= s._get_dependent() 2501 res |= s._get_dependent()
2495 2502
2496 if self.is_choice_sym: 2503 if self.is_choice_sym:
2497 # Choice symbols also depend (recursively) on their siblings. The 2504 # Choice symbols also depend (recursively) on their siblings. The
2498 # siblings are not included in 'dep' to avoid dependency loops. 2505 # siblings are not included in 'dep' to avoid dependency loops.
2499 for sibling in self.parent.actual_symbols: 2506 for sibling in self.parent.actual_symbols:
2500 if sibling is not self: 2507 if sibling is not self:
2501 res.add(sibling) 2508 res.add(sibling)
2502 res |= sibling.dep 2509 res |= sibling.dep
2503 for s in sibling.dep: 2510 for s in sibling.dep:
2504 res |= s._get_dependent() 2511 res |= s._get_dependent()
2505 2512
2506 self.cached_deps = res 2513 self.cached_deps = res
2507 return res 2514 return res
2508 2515
2509 def _has_auto_menu_dep_on(self, on): 2516 def _has_auto_menu_dep_on(self, on):
2510 """See Choice._determine_actual_symbols().""" 2517 """See Choice._determine_actual_symbols()."""
2511 if not isinstance(self.parent, Choice): 2518 if not isinstance(self.parent, Choice):
2512 _internal_error("Attempt to determine auto menu dependency for " 2519 _internal_error("Attempt to determine auto menu dependency for "
2513 "symbol ouside of choice.") 2520 "symbol ouside of choice.")
2514 2521
2515 if not self.prompts: 2522 if not self.prompts:
2516 # If we have no prompt, use the menu dependencies instead (what was 2523 # If we have no prompt, use the menu dependencies instead (what was
2517 # specified with 'depends on') 2524 # specified with 'depends on')
2518 return self.menu_dep is not None and \ 2525 return self.menu_dep is not None and \
2519 self.config._expr_depends_on(self.menu_dep, on) 2526 self.config._expr_depends_on(self.menu_dep, on)
2520 2527
2521 for _, cond_expr in self.prompts: 2528 for _, cond_expr in self.prompts:
2522 if self.config._expr_depends_on(cond_expr, on): 2529 if self.config._expr_depends_on(cond_expr, on):
2523 return True 2530 return True
2524 2531
2525 return False 2532 return False
2526 2533
2527 class Menu(Item): 2534 class Menu(Item):
2528 2535
2529 """Represents a menu statement.""" 2536 """Represents a menu statement."""
2530 2537
2531 # 2538 #
2532 # Public interface 2539 # Public interface
2533 # 2540 #
2534 2541
2535 def get_config(self): 2542 def get_config(self):
2536 """Return the Config instance this menu is from.""" 2543 """Return the Config instance this menu is from."""
2537 return self.config 2544 return self.config
2538 2545
2539 def get_title(self): 2546 def get_title(self):
2540 """Returns the title text of the menu.""" 2547 """Returns the title text of the menu."""
2541 return self.title 2548 return self.title
2542 2549
2543 def get_parent(self): 2550 def get_parent(self):
2544 """Returns the menu or choice statement that contains the menu, or 2551 """Returns the menu or choice statement that contains the menu, or
2545 None if the menu is at the top level. Note that if statements are 2552 None if the menu is at the top level. Note that if statements are
2546 treated as syntactic sugar and do not have an explicit class 2553 treated as syntactic sugar and do not have an explicit class
2547 representation.""" 2554 representation."""
2548 return self.parent 2555 return self.parent
2549 2556
2550 def get_location(self): 2557 def get_location(self):
2551 """Returns the location of the menu as a (filename, linenr) tuple, 2558 """Returns the location of the menu as a (filename, linenr) tuple,
2552 where filename is a string and linenr an int.""" 2559 where filename is a string and linenr an int."""
2553 return (self.filename, self.linenr) 2560 return (self.filename, self.linenr)
2554 2561
2555 def get_items(self, recursive=False): 2562 def get_items(self, recursive=False):
2556 """Returns a list containing the items (symbols, menus, choice 2563 """Returns a list containing the items (symbols, menus, choice
2557 statements and comments) in in the menu, in the same order that the 2564 statements and comments) in in the menu, in the same order that the
2558 items appear within the menu. 2565 items appear within the menu.
2559 2566
2560 recursive (default: False): True if items contained in items within the 2567 recursive (default: False): True if items contained in items within the
2561 menu should be included recursively (preorder).""" 2568 menu should be included recursively (preorder)."""
2562 2569
2563 if not recursive: 2570 if not recursive:
2564 return self.block 2571 return self.block
2565 2572
2566 res = [] 2573 res = []
2567 for item in self.block: 2574 for item in self.block:
2568 res.append(item) 2575 res.append(item)
2569 if isinstance(item, Menu): 2576 if isinstance(item, Menu):
2570 res.extend(item.get_items(True)) 2577 res.extend(item.get_items(True))
2571 elif isinstance(item, Choice): 2578 elif isinstance(item, Choice):
2572 res.extend(item.get_items()) 2579 res.extend(item.get_items())
2573 return res 2580 return res
2574 2581
2575 def get_symbols(self, recursive=False): 2582 def get_symbols(self, recursive=False):
2576 """Returns a list containing the symbols in the menu, in the same order 2583 """Returns a list containing the symbols in the menu, in the same order
2577 that they appear within the menu. 2584 that they appear within the menu.
2578 2585
2579 recursive (default: False): True if symbols contained in items within 2586 recursive (default: False): True if symbols contained in items within
2580 the menu should be included recursively.""" 2587 the menu should be included recursively."""
2581 2588
2582 return [item for item in self.get_items(recursive) if 2589 return [item for item in self.get_items(recursive) if
2583 isinstance(item, Symbol)] 2590 isinstance(item, Symbol)]
2584 2591
2585 def get_visibility(self): 2592 def get_visibility(self):
2586 """Returns the visibility of the menu. This also affects the visibility 2593 """Returns the visibility of the menu. This also affects the visibility
2587 of subitems. See also Symbol.get_visibility().""" 2594 of subitems. See also Symbol.get_visibility()."""
2588 return self.config._eval_expr(self.dep_expr) 2595 return self.config._eval_expr(self.dep_expr)
2589 2596
2590 def get_visible_if_visibility(self): 2597 def get_visible_if_visibility(self):
2591 """Returns the visibility the menu gets from its 'visible if' 2598 """Returns the visibility the menu gets from its 'visible if'
2592 condition. "y" if the menu has no 'visible if' condition.""" 2599 condition. "y" if the menu has no 'visible if' condition."""
2593 return self.config._eval_expr(self.visible_if_expr) 2600 return self.config._eval_expr(self.visible_if_expr)
2594 2601
2595 def get_referenced_symbols(self, refs_from_enclosing=False): 2602 def get_referenced_symbols(self, refs_from_enclosing=False):
2596 """See Symbol.get_referenced_symbols().""" 2603 """See Symbol.get_referenced_symbols()."""
2597 return self.all_referenced_syms if refs_from_enclosing else \ 2604 return self.all_referenced_syms if refs_from_enclosing else \
2598 self.referenced_syms 2605 self.referenced_syms
2599 2606
2600 def __str__(self): 2607 def __str__(self):
2601 """Returns a string containing various information about the menu.""" 2608 """Returns a string containing various information about the menu."""
2602 depends_on_str = self.config._expr_val_str(self.orig_deps, 2609 depends_on_str = self.config._expr_val_str(self.orig_deps,
2603 "(no dependencies)") 2610 "(no dependencies)")
2604 visible_if_str = self.config._expr_val_str(self.visible_if_expr, 2611 visible_if_str = self.config._expr_val_str(self.visible_if_expr,
2605 "(no dependencies)") 2612 "(no dependencies)")
2606 2613
2607 additional_deps_str = " " + \ 2614 additional_deps_str = " " + \
2608 self.config._expr_val_str(self.deps_from_containing, 2615 self.config._expr_val_str(self.deps_from_containing,
2609 "(no additional dependencies)") 2616 "(no additional dependencies)")
2610 2617
2611 return _lines("Menu", 2618 return _lines("Menu",
2612 "Title : " + self.title, 2619 "Title : " + self.title,
2613 "'depends on' dependencies : " + depends_on_str, 2620 "'depends on' dependencies : " + depends_on_str,
2614 "'visible if' dependencies : " + visible_if_str, 2621 "'visible if' dependencies : " + visible_if_str,
2615 "Additional dependencies from enclosing menus and " 2622 "Additional dependencies from enclosing menus and "
2616 "ifs:", 2623 "ifs:",
2617 additional_deps_str, 2624 additional_deps_str,
2618 "Location: {0}:{1}".format(self.filename, self.linenr)) 2625 "Location: {0}:{1}".format(self.filename, self.linenr))
2619 2626
2620 # 2627 #
2621 # Private methods 2628 # Private methods
2622 # 2629 #
2623 2630
2624 def __init__(self): 2631 def __init__(self):
2625 """Menu constructor -- not intended to be called directly by 2632 """Menu constructor -- not intended to be called directly by
2626 Kconfiglib clients.""" 2633 Kconfiglib clients."""
2627 2634
2628 self.title = None 2635 self.title = None
2629 self.dep_expr = None 2636 self.dep_expr = None
2630 self.visible_if_expr = None 2637 self.visible_if_expr = None
2631 self.block = None 2638 self.block = None
2632 self.config = None 2639 self.config = None
2633 self.parent = None 2640 self.parent = None
2634 2641
2635 # Dependency expression without dependencies from enclosing menus and 2642 # Dependency expression without dependencies from enclosing menus and
2636 # ifs propagated 2643 # ifs propagated
2637 self.orig_deps = None 2644 self.orig_deps = None
2638 2645
2639 # Dependencies inherited from containing menus and ifs 2646 # Dependencies inherited from containing menus and ifs
2640 self.deps_from_containing = None 2647 self.deps_from_containing = None
2641 # The set of symbols referenced by this menu (see 2648 # The set of symbols referenced by this menu (see
2642 # get_referenced_symbols()) 2649 # get_referenced_symbols())
2643 self.referenced_syms = set() 2650 self.referenced_syms = set()
2644 # Like 'referenced_syms', but includes symbols from 2651 # Like 'referenced_syms', but includes symbols from
2645 # dependencies inherited from enclosing menus and ifs 2652 # dependencies inherited from enclosing menus and ifs
2646 self.all_referenced_syms = None 2653 self.all_referenced_syms = None
2647 2654
2648 self.filename = None 2655 self.filename = None
2649 self.linenr = None 2656 self.linenr = None
2650 2657
2651 def _make_conf(self, append_fn): 2658 def _make_conf(self, append_fn):
2652 if self.config._eval_expr(self.dep_expr) != "n" and \ 2659 if self.config._eval_expr(self.dep_expr) != "n" and \
2653 self.config._eval_expr(self.visible_if_expr) != "n": 2660 self.config._eval_expr(self.visible_if_expr) != "n":
2654 append_fn("\n#\n# {0}\n#".format(self.title)) 2661 append_fn("\n#\n# {0}\n#".format(self.title))
2655 _make_block_conf(self.block, append_fn) 2662 _make_block_conf(self.block, append_fn)
2656 2663
2657 class Choice(Item): 2664 class Choice(Item):
2658 2665
2659 """Represents a choice statement. A choice can be in one of three modes: 2666 """Represents a choice statement. A choice can be in one of three modes:
2660 2667
2661 "n" - The choice is not visible and no symbols can be selected. 2668 "n" - The choice is not visible and no symbols can be selected.
2662 2669
2663 "m" - Any number of symbols can be set to "m". The rest will be "n". This 2670 "m" - Any number of symbols can be set to "m". The rest will be "n". This
2664 is safe since potentially conflicting options don't actually get 2671 is safe since potentially conflicting options don't actually get
2665 compiled into the kernel simultaneously with "m". 2672 compiled into the kernel simultaneously with "m".
2666 2673
2667 "y" - One symbol will be "y" while the rest are "n". 2674 "y" - One symbol will be "y" while the rest are "n".
2668 2675
2669 Only tristate choices can be in "m" mode, and the visibility of the choice 2676 Only tristate choices can be in "m" mode, and the visibility of the choice
2670 is an upper bound on the mode, so that e.g. a choice that depends on a 2677 is an upper bound on the mode, so that e.g. a choice that depends on a
2671 symbol with value "m" will be in "m" mode. 2678 symbol with value "m" will be in "m" mode.
2672 2679
2673 The mode changes automatically when a value is assigned to a symbol within 2680 The mode changes automatically when a value is assigned to a symbol within
2674 the choice. 2681 the choice.
2675 2682
2676 See Symbol.get_visibility() too.""" 2683 See Symbol.get_visibility() too."""
2677 2684
2678 # 2685 #
2679 # Public interface 2686 # Public interface
2680 # 2687 #
2681 2688
2682 def get_config(self): 2689 def get_config(self):
2683 """Returns the Config instance this choice is from.""" 2690 """Returns the Config instance this choice is from."""
2684 return self.config 2691 return self.config
2685 2692
2686 def get_name(self): 2693 def get_name(self):
2687 """For named choices, returns the name. Returns None for unnamed 2694 """For named choices, returns the name. Returns None for unnamed
2688 choices. No named choices appear anywhere in the kernel Kconfig files 2695 choices. No named choices appear anywhere in the kernel Kconfig files
2689 as of Linux 3.7.0-rc8.""" 2696 as of Linux 3.7.0-rc8."""
2690 return self.name 2697 return self.name
2691 2698
2692 def get_type(self): 2699 def get_type(self):
2693 """Returns the type of the choice. See Symbol.get_type().""" 2700 """Returns the type of the choice. See Symbol.get_type()."""
2694 return self.type 2701 return self.type
2695 2702
2696 def get_prompts(self): 2703 def get_prompts(self):
2697 """Returns a list of prompts defined for the choice, in the order they 2704 """Returns a list of prompts defined for the choice, in the order they
2698 appear in the configuration files. Returns the empty list for choices 2705 appear in the configuration files. Returns the empty list for choices
2699 with no prompt. 2706 with no prompt.
2700 2707
2701 This list will have a single entry for the vast majority of choices 2708 This list will have a single entry for the vast majority of choices
2702 having prompts, but having multiple prompts for a single choice is 2709 having prompts, but having multiple prompts for a single choice is
2703 possible through having multiple 'choice' entries for it (though I'm 2710 possible through having multiple 'choice' entries for it (though I'm
2704 not sure if that ever happens in practice).""" 2711 not sure if that ever happens in practice)."""
2705 return [prompt for prompt, _ in self.orig_prompts] 2712 return [prompt for prompt, _ in self.orig_prompts]
2706 2713
2707 def get_help(self): 2714 def get_help(self):
2708 """Returns the help text of the choice, or None if the choice has no 2715 """Returns the help text of the choice, or None if the choice has no
2709 help text.""" 2716 help text."""
2710 return self.help 2717 return self.help
2711 2718
2712 def get_parent(self): 2719 def get_parent(self):
2713 """Returns the menu or choice statement that contains the choice, or 2720 """Returns the menu or choice statement that contains the choice, or
2714 None if the choice is at the top level. Note that if statements are 2721 None if the choice is at the top level. Note that if statements are
2715 treated as syntactic sugar and do not have an explicit class 2722 treated as syntactic sugar and do not have an explicit class
2716 representation.""" 2723 representation."""
2717 return self.parent 2724 return self.parent
2718 2725
2719 def get_def_locations(self): 2726 def get_def_locations(self):
2720 """Returns a list of (filename, linenr) tuples, where filename (string) 2727 """Returns a list of (filename, linenr) tuples, where filename (string)
2721 and linenr (int) represent a location where the choice is defined. For 2728 and linenr (int) represent a location where the choice is defined. For
2722 the vast majority of choices (all of them as of Linux 3.7.0-rc8) this 2729 the vast majority of choices (all of them as of Linux 3.7.0-rc8) this
2723 list will only contain one element, but its possible for named choices 2730 list will only contain one element, but its possible for named choices
2724 to be defined in multiple locations.""" 2731 to be defined in multiple locations."""
2725 return self.def_locations 2732 return self.def_locations
2726 2733
2727 def get_selection(self): 2734 def get_selection(self):
2728 """Returns the symbol selected (either by the user or through 2735 """Returns the symbol selected (either by the user or through
2729 defaults), or None if either no symbol is selected or the mode is not 2736 defaults), or None if either no symbol is selected or the mode is not
2730 "y".""" 2737 "y"."""
2731 if self.cached_selection is not None: 2738 if self.cached_selection is not None:
2732 if self.cached_selection == NO_SELECTION: 2739 if self.cached_selection == NO_SELECTION:
2733 return None 2740 return None
2734 return self.cached_selection 2741 return self.cached_selection
2735 2742
2736 if self.get_mode() != "y": 2743 if self.get_mode() != "y":
2737 return self._cache_ret(None) 2744 return self._cache_ret(None)
2738 2745
2739 # User choice available? 2746 # User choice available?
2740 if self.user_val is not None and _get_visibility(self.user_val) == "y": 2747 if self.user_val is not None and _get_visibility(self.user_val) == "y":
2741 return self._cache_ret(self.user_val) 2748 return self._cache_ret(self.user_val)
2742 2749
2743 if self.optional: 2750 if self.optional:
2744 return self._cache_ret(None) 2751 return self._cache_ret(None)
2745 2752
2746 return self._cache_ret(self.get_selection_from_defaults()) 2753 return self._cache_ret(self.get_selection_from_defaults())
2747 2754
2748 def get_selection_from_defaults(self): 2755 def get_selection_from_defaults(self):
2749 """Like Choice.get_selection(), but acts as if no symbol has been 2756 """Like Choice.get_selection(), but acts as if no symbol has been
2750 selected by the user and no 'optional' flag is in effect.""" 2757 selected by the user and no 'optional' flag is in effect."""
2751 2758
2752 if not self.actual_symbols: 2759 if not self.actual_symbols:
2753 return None 2760 return None
2754 2761
2755 for symbol, cond_expr in self.def_exprs: 2762 for symbol, cond_expr in self.def_exprs:
2756 if self.config._eval_expr(cond_expr) != "n": 2763 if self.config._eval_expr(cond_expr) != "n":
2757 chosen_symbol = symbol 2764 chosen_symbol = symbol
2758 break 2765 break
2759 else: 2766 else:
2760 chosen_symbol = self.actual_symbols[0] 2767 chosen_symbol = self.actual_symbols[0]
2761 2768
2762 # Is the chosen symbol visible? 2769 # Is the chosen symbol visible?
2763 if _get_visibility(chosen_symbol) != "n": 2770 if _get_visibility(chosen_symbol) != "n":
2764 return chosen_symbol 2771 return chosen_symbol
2765 # Otherwise, pick the first visible symbol 2772 # Otherwise, pick the first visible symbol
2766 for sym in self.actual_symbols: 2773 for sym in self.actual_symbols:
2767 if _get_visibility(sym) != "n": 2774 if _get_visibility(sym) != "n":
2768 return sym 2775 return sym
2769 return None 2776 return None
2770 2777
2771 def get_user_selection(self): 2778 def get_user_selection(self):
2772 """If the choice is in "y" mode and has a user-selected symbol, returns 2779 """If the choice is in "y" mode and has a user-selected symbol, returns
2773 that symbol. Otherwise, returns None.""" 2780 that symbol. Otherwise, returns None."""
2774 return self.user_val 2781 return self.user_val
2775 2782
2776 def get_items(self): 2783 def get_items(self):
2777 """Gets all items contained in the choice in the same order as within 2784 """Gets all items contained in the choice in the same order as within
2778 the configuration ("items" instead of "symbols" since choices and 2785 the configuration ("items" instead of "symbols" since choices and
2779 comments might appear within choices. This only happens in one place as 2786 comments might appear within choices. This only happens in one place as
2780 of Linux 3.7.0-rc8, in drivers/usb/gadget/Kconfig).""" 2787 of Linux 3.7.0-rc8, in drivers/usb/gadget/Kconfig)."""
2781 return self.block 2788 return self.block
2782 2789
2783 def get_symbols(self): 2790 def get_symbols(self):
2784 """Returns a list containing the choice's symbols. 2791 """Returns a list containing the choice's symbols.
2785 2792
2786 A quirk (perhaps a bug) of Kconfig is that you can put items within a 2793 A quirk (perhaps a bug) of Kconfig is that you can put items within a
2787 choice that will not be considered members of the choice insofar as 2794 choice that will not be considered members of the choice insofar as
2788 selection is concerned. This happens for example if one symbol within a 2795 selection is concerned. This happens for example if one symbol within a
2789 choice 'depends on' the symbol preceding it, or if you put non-symbol 2796 choice 'depends on' the symbol preceding it, or if you put non-symbol
2790 items within choices. 2797 items within choices.
2791 2798
2792 As of Linux 3.7.0-rc8, this seems to be used intentionally in one 2799 As of Linux 3.7.0-rc8, this seems to be used intentionally in one
2793 place: drivers/usb/gadget/Kconfig. 2800 place: drivers/usb/gadget/Kconfig.
2794 2801
2795 This function returns the "proper" symbols of the choice in the order 2802 This function returns the "proper" symbols of the choice in the order
2796 they appear in the choice, excluding such items. If you want all items 2803 they appear in the choice, excluding such items. If you want all items
2797 in the choice, use get_items().""" 2804 in the choice, use get_items()."""
2798 return self.actual_symbols 2805 return self.actual_symbols
2799 2806
2800 def get_referenced_symbols(self, refs_from_enclosing=False): 2807 def get_referenced_symbols(self, refs_from_enclosing=False):
2801 """See Symbol.get_referenced_symbols().""" 2808 """See Symbol.get_referenced_symbols()."""
2802 return self.all_referenced_syms if refs_from_enclosing else \ 2809 return self.all_referenced_syms if refs_from_enclosing else \
2803 self.referenced_syms 2810 self.referenced_syms
2804 2811
2805 def get_visibility(self): 2812 def get_visibility(self):
2806 """Returns the visibility of the choice statement: one of "n", "m" or 2813 """Returns the visibility of the choice statement: one of "n", "m" or
2807 "y". This acts as an upper limit on the mode of the choice (though bool 2814 "y". This acts as an upper limit on the mode of the choice (though bool
2808 choices can only have the mode "y"). See the class documentation for an 2815 choices can only have the mode "y"). See the class documentation for an
2809 explanation of modes.""" 2816 explanation of modes."""
2810 return _get_visibility(self) 2817 return _get_visibility(self)
2811 2818
2812 def get_mode(self): 2819 def get_mode(self):
2813 """Returns the mode of the choice. See the class documentation for 2820 """Returns the mode of the choice. See the class documentation for
2814 an explanation of modes.""" 2821 an explanation of modes."""
2815 minimum_mode = "n" if self.optional else "m" 2822 minimum_mode = "n" if self.optional else "m"
2816 mode = self.user_mode if self.user_mode is not None else minimum_mode 2823 mode = self.user_mode if self.user_mode is not None else minimum_mode
2817 mode = self.config._eval_min(mode, _get_visibility(self)) 2824 mode = self.config._eval_min(mode, _get_visibility(self))
2818 2825
2819 # Promote "m" to "y" for boolean choices 2826 # Promote "m" to "y" for boolean choices
2820 if mode == "m" and self.type == BOOL: 2827 if mode == "m" and self.type == BOOL:
2821 return "y" 2828 return "y"
2822 2829
2823 return mode 2830 return mode
2824 2831
2825 def is_optional(self): 2832 def is_optional(self):
2826 """Returns True if the choice has the 'optional' flag set (and so will 2833 """Returns True if the choice has the 'optional' flag set (and so will
2827 default to "n" mode).""" 2834 default to "n" mode)."""
2828 return self.optional 2835 return self.optional
2829 2836
2830 def __str__(self): 2837 def __str__(self):
2831 """Returns a string containing various information about the choice 2838 """Returns a string containing various information about the choice
2832 statement.""" 2839 statement."""
2833 return self.config._get_sym_or_choice_str(self) 2840 return self.config._get_sym_or_choice_str(self)
2834 2841
2835 # 2842 #
2836 # Private methods 2843 # Private methods
2837 # 2844 #
2838 2845
2839 def __init__(self): 2846 def __init__(self):
2840 """Choice constructor -- not intended to be called directly by 2847 """Choice constructor -- not intended to be called directly by
2841 Kconfiglib clients.""" 2848 Kconfiglib clients."""
2842 2849
2843 self.name = None # Yes, choices can be named 2850 self.name = None # Yes, choices can be named
2844 self.type = UNKNOWN 2851 self.type = UNKNOWN
2845 self.prompts = [] 2852 self.prompts = []
2846 self.def_exprs = [] # 'default' properties 2853 self.def_exprs = [] # 'default' properties
2847 self.help = None # Help text 2854 self.help = None # Help text
2848 self.block = None # List of contained items 2855 self.block = None # List of contained items
2849 self.config = None 2856 self.config = None
2850 self.parent = None 2857 self.parent = None
2851 2858
2852 self.user_val = None 2859 self.user_val = None
2853 self.user_mode = None 2860 self.user_mode = None
2854 2861
2855 # We need to filter out symbols that appear within the choice block but 2862 # We need to filter out symbols that appear within the choice block but
2856 # are not considered choice items (see 2863 # are not considered choice items (see
2857 # Choice._determine_actual_symbols()) This list holds the "actual" 2864 # Choice._determine_actual_symbols()) This list holds the "actual"
2858 # choice items. 2865 # choice items.
2859 self.actual_symbols = [] 2866 self.actual_symbols = []
2860 2867
2861 # The prompts and default values without any dependencies from 2868 # The prompts and default values without any dependencies from
2862 # enclosing menus and ifs propagated 2869 # enclosing menus and ifs propagated
2863 self.orig_prompts = [] 2870 self.orig_prompts = []
2864 self.orig_def_exprs = [] 2871 self.orig_def_exprs = []
2865 2872
2866 # Dependencies inherited from containing menus and ifs 2873 # Dependencies inherited from containing menus and ifs
2867 self.deps_from_containing = None 2874 self.deps_from_containing = None
2868 # The set of symbols referenced by this choice (see 2875 # The set of symbols referenced by this choice (see
2869 # get_referenced_symbols()) 2876 # get_referenced_symbols())
2870 self.referenced_syms = set() 2877 self.referenced_syms = set()
2871 # Like 'referenced_syms', but includes symbols from 2878 # Like 'referenced_syms', but includes symbols from
2872 # dependencies inherited from enclosing menus and ifs 2879 # dependencies inherited from enclosing menus and ifs
2873 self.all_referenced_syms = set() 2880 self.all_referenced_syms = set()
2874 2881
2875 # See Choice.get_def_locations() 2882 # See Choice.get_def_locations()
2876 self.def_locations = [] 2883 self.def_locations = []
2877 2884
2878 # Cached values 2885 # Cached values
2879 self.cached_selection = None 2886 self.cached_selection = None
2880 self.cached_visibility = None 2887 self.cached_visibility = None
2881 2888
2882 self.optional = False 2889 self.optional = False
2883 2890
2884 def _determine_actual_symbols(self): 2891 def _determine_actual_symbols(self):
2885 """If a symbol's visibility depends on the preceding symbol within a 2892 """If a symbol's visibility depends on the preceding symbol within a
2886 choice, it is no longer viewed as a choice item. (This is quite 2893 choice, it is no longer viewed as a choice item. (This is quite
2887 possibly a bug, but some things consciously use it... ugh. It stems 2894 possibly a bug, but some things consciously use it... ugh. It stems
2888 from automatic submenu creation.) In addition, it's possible to have 2895 from automatic submenu creation.) In addition, it's possible to have
2889 choices and comments within choices, and those shouldn't be considered 2896 choices and comments within choices, and those shouldn't be considered
2890 choice items either. Only drivers/usb/gadget/Kconfig seems to depend on 2897 choice items either. Only drivers/usb/gadget/Kconfig seems to depend on
2891 any of this. This method computes the "actual" items in the choice and 2898 any of this. This method computes the "actual" items in the choice and
2892 sets the is_choice_sym flag on them (retrieved via is_choice_symbol()). 2899 sets the is_choice_sym flag on them (retrieved via is_choice_symbol()).
2893 2900
2894 Don't let this scare you: an earlier version simply checked for a 2901 Don't let this scare you: an earlier version simply checked for a
2895 sequence of symbols where all symbols after the first appeared in the 2902 sequence of symbols where all symbols after the first appeared in the
2896 'depends on' expression of the first, and that worked fine. The added 2903 'depends on' expression of the first, and that worked fine. The added
2897 complexity is to be future-proof in the event that 2904 complexity is to be future-proof in the event that
2898 drivers/usb/gadget/Kconfig turns even more sinister. It might very well 2905 drivers/usb/gadget/Kconfig turns even more sinister. It might very well
2899 be overkilling things (especially if that file is refactored ;).""" 2906 be overkilling things (especially if that file is refactored ;)."""
2900 2907
2901 # Items might depend on each other in a tree structure, so we need a 2908 # Items might depend on each other in a tree structure, so we need a
2902 # stack to keep track of the current tentative parent 2909 # stack to keep track of the current tentative parent
2903 stack = [] 2910 stack = []
2904 2911
2905 for item in self.block: 2912 for item in self.block:
2906 if not isinstance(item, Symbol): 2913 if not isinstance(item, Symbol):
2907 stack = [] 2914 stack = []
2908 continue 2915 continue
2909 2916
2910 while stack: 2917 while stack:
2911 if item._has_auto_menu_dep_on(stack[-1]): 2918 if item._has_auto_menu_dep_on(stack[-1]):
2912 # The item should not be viewed as a choice item, so don't 2919 # The item should not be viewed as a choice item, so don't
2913 # set item.is_choice_sym 2920 # set item.is_choice_sym
2914 stack.append(item) 2921 stack.append(item)
2915 break 2922 break
2916 else: 2923 else:
2917 stack.pop() 2924 stack.pop()
2918 else: 2925 else:
2919 item.is_choice_sym = True 2926 item.is_choice_sym = True
2920 self.actual_symbols.append(item) 2927 self.actual_symbols.append(item)
2921 stack.append(item) 2928 stack.append(item)
2922 2929
2923 def _cache_ret(self, selection): 2930 def _cache_ret(self, selection):
2924 # As None is used to indicate the lack of a cached value we can't use 2931 # As None is used to indicate the lack of a cached value we can't use
2925 # that to cache the fact that the choice has no selection. Instead, we 2932 # that to cache the fact that the choice has no selection. Instead, we
2926 # use the symbolic constant NO_SELECTION. 2933 # use the symbolic constant NO_SELECTION.
2927 if selection is None: 2934 if selection is None:
2928 self.cached_selection = NO_SELECTION 2935 self.cached_selection = NO_SELECTION
2929 else: 2936 else:
2930 self.cached_selection = selection 2937 self.cached_selection = selection
2931 2938
2932 return selection 2939 return selection
2933 2940
2934 def _invalidate(self): 2941 def _invalidate(self):
2935 self.cached_selection = None 2942 self.cached_selection = None
2936 self.cached_visibility = None 2943 self.cached_visibility = None
2937 2944
2938 def _unset_user_value(self): 2945 def _unset_user_value(self):
2939 self._invalidate() 2946 self._invalidate()
2940 self.user_val = None 2947 self.user_val = None
2941 self.user_mode = None 2948 self.user_mode = None
2942 2949
2943 def _make_conf(self, append_fn): 2950 def _make_conf(self, append_fn):
2944 _make_block_conf(self.block, append_fn) 2951 _make_block_conf(self.block, append_fn)
2945 2952
2946 class Comment(Item): 2953 class Comment(Item):
2947 2954
2948 """Represents a comment statement.""" 2955 """Represents a comment statement."""
2949 2956
2950 # 2957 #
2951 # Public interface 2958 # Public interface
2952 # 2959 #
2953 2960
2954 def get_config(self): 2961 def get_config(self):
2955 """Returns the Config instance this comment is from.""" 2962 """Returns the Config instance this comment is from."""
2956 return self.config 2963 return self.config
2957 2964
2958 def get_text(self): 2965 def get_text(self):
2959 """Returns the text of the comment.""" 2966 """Returns the text of the comment."""
2960 return self.text 2967 return self.text
2961 2968
2962 def get_parent(self): 2969 def get_parent(self):
2963 """Returns the menu or choice statement that contains the comment, or 2970 """Returns the menu or choice statement that contains the comment, or
2964 None if the comment is at the top level. Note that if statements are 2971 None if the comment is at the top level. Note that if statements are
2965 treated as syntactic sugar and do not have an explicit class 2972 treated as syntactic sugar and do not have an explicit class
2966 representation.""" 2973 representation."""
2967 return self.parent 2974 return self.parent
2968 2975
2969 def get_location(self): 2976 def get_location(self):
2970 """Returns the location of the comment as a (filename, linenr) tuple, 2977 """Returns the location of the comment as a (filename, linenr) tuple,
2971 where filename is a string and linenr an int.""" 2978 where filename is a string and linenr an int."""
2972 return (self.filename, self.linenr) 2979 return (self.filename, self.linenr)
2973 2980
2974 def get_visibility(self): 2981 def get_visibility(self):
2975 """Returns the visibility of the comment. See also 2982 """Returns the visibility of the comment. See also
2976 Symbol.get_visibility().""" 2983 Symbol.get_visibility()."""
2977 return self.config._eval_expr(self.dep_expr) 2984 return self.config._eval_expr(self.dep_expr)
2978 2985
2979 def get_referenced_symbols(self, refs_from_enclosing=False): 2986 def get_referenced_symbols(self, refs_from_enclosing=False):
2980 """See Symbol.get_referenced_symbols().""" 2987 """See Symbol.get_referenced_symbols()."""
2981 return self.all_referenced_syms if refs_from_enclosing else \ 2988 return self.all_referenced_syms if refs_from_enclosing else \
2982 self.referenced_syms 2989 self.referenced_syms
2983 2990
2984 def __str__(self): 2991 def __str__(self):
2985 """Returns a string containing various information about the 2992 """Returns a string containing various information about the
2986 comment.""" 2993 comment."""
2987 dep_str = self.config._expr_val_str(self.orig_deps, 2994 dep_str = self.config._expr_val_str(self.orig_deps,
2988 "(no dependencies)") 2995 "(no dependencies)")
2989 2996
2990 additional_deps_str = " " + \ 2997 additional_deps_str = " " + \
2991 self.config._expr_val_str(self.deps_from_containing, 2998 self.config._expr_val_str(self.deps_from_containing,
2992 "(no additional dependencies)") 2999 "(no additional dependencies)")
2993 3000
2994 return _lines("Comment", 3001 return _lines("Comment",
2995 "Text: " + str(self.text), 3002 "Text: " + str(self.text),
2996 "Dependencies: " + dep_str, 3003 "Dependencies: " + dep_str,
2997 "Additional dependencies from enclosing menus and " 3004 "Additional dependencies from enclosing menus and "
2998 "ifs:", 3005 "ifs:",
2999 additional_deps_str, 3006 additional_deps_str,
3000 "Location: {0}:{1}".format(self.filename, self.linenr)) 3007 "Location: {0}:{1}".format(self.filename, self.linenr))
3001 3008
3002 # 3009 #
3003 # Private methods 3010 # Private methods
3004 # 3011 #
3005 3012
3006 def __init__(self): 3013 def __init__(self):
3007 """Comment constructor -- not intended to be called directly by 3014 """Comment constructor -- not intended to be called directly by
3008 Kconfiglib clients.""" 3015 Kconfiglib clients."""
3009 3016
3010 self.text = None 3017 self.text = None
3011 self.dep_expr = None 3018 self.dep_expr = None
3012 self.config = None 3019 self.config = None
3013 self.parent = None 3020 self.parent = None
3014 3021
3015 # Dependency expression without dependencies from enclosing menus and 3022 # Dependency expression without dependencies from enclosing menus and
3016 # ifs propagated 3023 # ifs propagated
3017 self.orig_deps = None 3024 self.orig_deps = None
3018 3025
3019 # Dependencies inherited from containing menus and ifs 3026 # Dependencies inherited from containing menus and ifs
3020 self.deps_from_containing = None 3027 self.deps_from_containing = None
3021 # The set of symbols referenced by this comment (see 3028 # The set of symbols referenced by this comment (see
3022 # get_referenced_symbols()) 3029 # get_referenced_symbols())
3023 self.referenced_syms = set() 3030 self.referenced_syms = set()
3024 # Like 'referenced_syms', but includes symbols from 3031 # Like 'referenced_syms', but includes symbols from
3025 # dependencies inherited from enclosing menus and ifs 3032 # dependencies inherited from enclosing menus and ifs
3026 self.all_referenced_syms = None 3033 self.all_referenced_syms = None
3027 3034
3028 self.filename = None 3035 self.filename = None
3029 self.linenr = None 3036 self.linenr = None
3030 3037
3031 def _make_conf(self, append_fn): 3038 def _make_conf(self, append_fn):
3032 if self.config._eval_expr(self.dep_expr) != "n": 3039 if self.config._eval_expr(self.dep_expr) != "n":
3033 append_fn("\n#\n# {0}\n#".format(self.text)) 3040 append_fn("\n#\n# {0}\n#".format(self.text))
3034 3041
3035 class Kconfig_Syntax_Error(Exception): 3042 class Kconfig_Syntax_Error(Exception):
3036 """Exception raised for syntax errors.""" 3043 """Exception raised for syntax errors."""
3037 pass 3044 pass
3038 3045
3039 class Internal_Error(Exception): 3046 class Internal_Error(Exception):
3040 """Exception raised for internal errors.""" 3047 """Exception raised for internal errors."""
3041 pass 3048 pass
3042 3049
3043 # 3050 #
3044 # Public functions 3051 # Public functions
3045 # 3052 #
3046 3053
3047 def tri_less(v1, v2): 3054 def tri_less(v1, v2):
3048 """Returns True if the tristate v1 is less than the tristate v2, where "n", 3055 """Returns True if the tristate v1 is less than the tristate v2, where "n",
3049 "m" and "y" are ordered from lowest to highest.""" 3056 "m" and "y" are ordered from lowest to highest."""
3050 return TRI_TO_INT[v1] < TRI_TO_INT[v2] 3057 return TRI_TO_INT[v1] < TRI_TO_INT[v2]
3051 3058
3052 def tri_less_eq(v1, v2): 3059 def tri_less_eq(v1, v2):
3053 """Returns True if the tristate v1 is less than or equal to the tristate 3060 """Returns True if the tristate v1 is less than or equal to the tristate
3054 v2, where "n", "m" and "y" are ordered from lowest to highest.""" 3061 v2, where "n", "m" and "y" are ordered from lowest to highest."""
3055 return TRI_TO_INT[v1] <= TRI_TO_INT[v2] 3062 return TRI_TO_INT[v1] <= TRI_TO_INT[v2]
3056 3063
3057 def tri_greater(v1, v2): 3064 def tri_greater(v1, v2):
3058 """Returns True if the tristate v1 is greater than the tristate v2, where 3065 """Returns True if the tristate v1 is greater than the tristate v2, where
3059 "n", "m" and "y" are ordered from lowest to highest.""" 3066 "n", "m" and "y" are ordered from lowest to highest."""
3060 return TRI_TO_INT[v1] > TRI_TO_INT[v2] 3067 return TRI_TO_INT[v1] > TRI_TO_INT[v2]
3061 3068
3062 def tri_greater_eq(v1, v2): 3069 def tri_greater_eq(v1, v2):
3063 """Returns True if the tristate v1 is greater than or equal to the tristate 3070 """Returns True if the tristate v1 is greater than or equal to the tristate
3064 v2, where "n", "m" and "y" are ordered from lowest to highest.""" 3071 v2, where "n", "m" and "y" are ordered from lowest to highest."""
3065 return TRI_TO_INT[v1] >= TRI_TO_INT[v2] 3072 return TRI_TO_INT[v1] >= TRI_TO_INT[v2]
3066 3073
3067 # 3074 #
3068 # Internal classes 3075 # Internal classes
3069 # 3076 #
3070 3077
3071 class _Feed(object): 3078 class _Feed(object):
3072 3079
3073 """Class for working with sequences in a stream-like fashion; handy for 3080 """Class for working with sequences in a stream-like fashion; handy for
3074 tokens.""" 3081 tokens."""
3075 3082
3076 # This would be more helpful on the item classes, but would remove some 3083 # This would be more helpful on the item classes, but would remove some
3077 # flexibility 3084 # flexibility
3078 __slots__ = ['items', 'length', 'i'] 3085 __slots__ = ['items', 'length', 'i']
3079 3086
3080 def __init__(self, items): 3087 def __init__(self, items):
3081 self.items = items 3088 self.items = items
3082 self.length = len(self.items) 3089 self.length = len(self.items)
3083 self.i = 0 3090 self.i = 0
3084 3091
3085 def get_next(self): 3092 def get_next(self):
3086 if self.i >= self.length: 3093 if self.i >= self.length:
3087 return None 3094 return None
3088 item = self.items[self.i] 3095 item = self.items[self.i]
3089 self.i += 1 3096 self.i += 1
3090 return item 3097 return item
3091 3098
3092 def peek_next(self): 3099 def peek_next(self):
3093 return None if self.i >= self.length else self.items[self.i] 3100 return None if self.i >= self.length else self.items[self.i]
3094 3101
3095 def check(self, token): 3102 def check(self, token):
3096 """Check if the next token is 'token'. If so, remove it from the token 3103 """Check if the next token is 'token'. If so, remove it from the token
3097 feed and return True. Otherwise, leave it in and return False.""" 3104 feed and return True. Otherwise, leave it in and return False."""
3098 if self.i < self.length and self.items[self.i] == token: 3105 if self.i < self.length and self.items[self.i] == token:
3099 self.i += 1 3106 self.i += 1
3100 return True 3107 return True
3101 return False 3108 return False
3102 3109
3103 def unget_all(self): 3110 def unget_all(self):
3104 self.i = 0 3111 self.i = 0
3105 3112
3106 class _FileFeed(object): 3113 class _FileFeed(object):
3107 3114
3108 """Feeds lines from a file. Keeps track of the filename and current line 3115 """Feeds lines from a file. Keeps track of the filename and current line
3109 number. Joins any line ending in \\ with the following line. We need to be 3116 number. Joins any line ending in \\ with the following line. We need to be
3110 careful to get the line number right in the presence of continuation 3117 careful to get the line number right in the presence of continuation
3111 lines.""" 3118 lines."""
3112 3119
3113 __slots__ = ['filename', 'lines', 'length', 'linenr'] 3120 __slots__ = ['filename', 'lines', 'length', 'linenr']
3114 3121
3115 def __init__(self, filename): 3122 def __init__(self, filename):
3116 self.filename = _clean_up_path(filename) 3123 self.filename = _clean_up_path(filename)
3117 with open(filename, "r") as f: 3124 with open(filename, "r") as f:
3118 # No interleaving of I/O and processing yet. Don't know if it would 3125 # No interleaving of I/O and processing yet. Don't know if it would
3119 # help. 3126 # help.
3120 self.lines = f.readlines() 3127 self.lines = f.readlines()
3121 self.length = len(self.lines) 3128 self.length = len(self.lines)
3122 self.linenr = 0 3129 self.linenr = 0
3123 3130
3124 def get_next(self): 3131 def get_next(self):
3125 if self.linenr >= self.length: 3132 if self.linenr >= self.length:
3126 return None 3133 return None
3127 line = self.lines[self.linenr] 3134 line = self.lines[self.linenr]
3128 self.linenr += 1 3135 self.linenr += 1
3129 while line.endswith("\\\n"): 3136 while line.endswith("\\\n"):
3130 line = line[:-2] + self.lines[self.linenr] 3137 line = line[:-2] + self.lines[self.linenr]
3131 self.linenr += 1 3138 self.linenr += 1
3132 return line 3139 return line
3133 3140
3134 def peek_next(self): 3141 def peek_next(self):
3135 linenr = self.linenr 3142 linenr = self.linenr
3136 if linenr >= self.length: 3143 if linenr >= self.length:
3137 return None 3144 return None
3138 line = self.lines[linenr] 3145 line = self.lines[linenr]
3139 while line.endswith("\\\n"): 3146 while line.endswith("\\\n"):
3140 linenr += 1 3147 linenr += 1
3141 line = line[:-2] + self.lines[linenr] 3148 line = line[:-2] + self.lines[linenr]
3142 return line 3149 return line
3143 3150
3144 def unget(self): 3151 def unget(self):
3145 self.linenr -= 1 3152 self.linenr -= 1
3146 while self.lines[self.linenr].endswith("\\\n"): 3153 while self.lines[self.linenr].endswith("\\\n"):
3147 self.linenr -= 1 3154 self.linenr -= 1
3148 3155
3149 def next_nonblank(self): 3156 def next_nonblank(self):
3150 """Removes lines up to and including the next non-blank (not all-space) 3157 """Removes lines up to and including the next non-blank (not all-space)
3151 line and returns it. Returns None if there are no more non-blank 3158 line and returns it. Returns None if there are no more non-blank
3152 lines.""" 3159 lines."""
3153 while 1: 3160 while 1:
3154 line = self.get_next() 3161 line = self.get_next()
3155 if line is None or not line.isspace(): 3162 if line is None or not line.isspace():
3156 return line 3163 return line
3157 3164
3158 # 3165 #
3159 # Internal functions 3166 # Internal functions
3160 # 3167 #
3161 3168
3162 def _get_visibility(sc): 3169 def _get_visibility(sc):
3163 """Symbols and Choices have a "visibility" that acts as an upper bound on 3170 """Symbols and Choices have a "visibility" that acts as an upper bound on
3164 the values a user can set for them, corresponding to the visibility in e.g. 3171 the values a user can set for them, corresponding to the visibility in e.g.
3165 'make menuconfig'. This function calculates the visibility for the Symbol 3172 'make menuconfig'. This function calculates the visibility for the Symbol
3166 or Choice 'sc' -- the logic is nearly identical.""" 3173 or Choice 'sc' -- the logic is nearly identical."""
3167 if sc.cached_visibility is None: 3174 if sc.cached_visibility is None:
3168 vis = "n" 3175 vis = "n"
3169 for _, cond_expr in sc.prompts: 3176 for _, cond_expr in sc.prompts:
3170 vis = sc.config._eval_max(vis, cond_expr) 3177 vis = sc.config._eval_max(vis, cond_expr)
3171 3178
3172 if isinstance(sc, Symbol) and sc.is_choice_sym: 3179 if isinstance(sc, Symbol) and sc.is_choice_sym:
3173 vis = sc.config._eval_min(vis, _get_visibility(sc.parent)) 3180 vis = sc.config._eval_min(vis, _get_visibility(sc.parent))
3174 3181
3175 # Promote "m" to "y" if we're dealing with a non-tristate 3182 # Promote "m" to "y" if we're dealing with a non-tristate
3176 if vis == "m" and sc.type != TRISTATE: 3183 if vis == "m" and sc.type != TRISTATE:
3177 vis = "y" 3184 vis = "y"
3178 3185
3179 sc.cached_visibility = vis 3186 sc.cached_visibility = vis
3180 3187
3181 return sc.cached_visibility 3188 return sc.cached_visibility
3182 3189
3183 def _make_and(e1, e2): 3190 def _make_and(e1, e2):
3184 """Constructs an AND (&&) expression. Performs trivial simplification. 3191 """Constructs an AND (&&) expression. Performs trivial simplification.
3185 Nones equate to 'y'. 3192 Nones equate to 'y'.
3186 3193
3187 Note: returns None if e1 == e2 == None.""" 3194 Note: returns None if e1 == e2 == None."""
3188 if e1 is None or e1 == "y": 3195 if e1 is None or e1 == "y":
3189 return e2 3196 return e2
3190 if e2 is None or e2 == "y": 3197 if e2 is None or e2 == "y":
3191 return e1 3198 return e1
3192 3199
3193 # Prefer to merge argument lists if possible to reduce the number of nodes 3200 # Prefer to merge argument lists if possible to reduce the number of nodes
3194 3201
3195 if isinstance(e1, tuple) and e1[0] == AND: 3202 if isinstance(e1, tuple) and e1[0] == AND:
3196 if isinstance(e2, tuple) and e2[0] == AND: 3203 if isinstance(e2, tuple) and e2[0] == AND:
3197 return (AND, e1[1] + e2[1]) 3204 return (AND, e1[1] + e2[1])
3198 return (AND, e1[1] + [e2]) 3205 return (AND, e1[1] + [e2])
3199 3206
3200 if isinstance(e2, tuple) and e2[0] == AND: 3207 if isinstance(e2, tuple) and e2[0] == AND:
3201 return (AND, e2[1] + [e1]) 3208 return (AND, e2[1] + [e1])
3202 3209
3203 return (AND, [e1, e2]) 3210 return (AND, [e1, e2])
3204 3211
3205 def _make_or(e1, e2): 3212 def _make_or(e1, e2):
3206 """Constructs an OR (||) expression. Performs trivial simplification and 3213 """Constructs an OR (||) expression. Performs trivial simplification and
3207 avoids Nones. Nones equate to 'y', which is usually what we want, but needs 3214 avoids Nones. Nones equate to 'y', which is usually what we want, but needs
3208 to be kept in mind.""" 3215 to be kept in mind."""
3209 3216
3210 # Perform trivial simplification and avoid None's (which 3217 # Perform trivial simplification and avoid None's (which
3211 # correspond to y's) 3218 # correspond to y's)
3212 if e1 is None or e2 is None or e1 == "y" or e2 == "y": 3219 if e1 is None or e2 is None or e1 == "y" or e2 == "y":
3213 return "y" 3220 return "y"
3214 if e1 == "n": 3221 if e1 == "n":
3215 return e2 3222 return e2
3216 3223
3217 # Prefer to merge argument lists if possible to reduce the number of nodes 3224 # Prefer to merge argument lists if possible to reduce the number of nodes
3218 3225
3219 if isinstance(e1, tuple) and e1[0] == OR: 3226 if isinstance(e1, tuple) and e1[0] == OR:
3220 if isinstance(e2, tuple) and e2[0] == OR: 3227 if isinstance(e2, tuple) and e2[0] == OR:
3221 return (OR, e1[1] + e2[1]) 3228 return (OR, e1[1] + e2[1])
3222 return (OR, e1[1] + [e2]) 3229 return (OR, e1[1] + [e2])
3223 3230
3224 if isinstance(e2, tuple) and e2[0] == OR: 3231 if isinstance(e2, tuple) and e2[0] == OR:
3225 return (OR, e2[1] + [e1]) 3232 return (OR, e2[1] + [e1])
3226 3233
3227 return (OR, [e1, e2]) 3234 return (OR, [e1, e2])
3228 3235
3229 def _get_expr_syms_rec(expr, res): 3236 def _get_expr_syms_rec(expr, res):
3230 """_get_expr_syms() helper. Recurses through expressions.""" 3237 """_get_expr_syms() helper. Recurses through expressions."""
3231 if isinstance(expr, Symbol): 3238 if isinstance(expr, Symbol):
3232 res.add(expr) 3239 res.add(expr)
3233 elif isinstance(expr, str): 3240 elif isinstance(expr, str):
3234 return 3241 return
3235 elif expr[0] == AND or expr[0] == OR: 3242 elif expr[0] == AND or expr[0] == OR:
3236 for term in expr[1]: 3243 for term in expr[1]:
3237 _get_expr_syms_rec(term, res) 3244 _get_expr_syms_rec(term, res)
3238 elif expr[0] == NOT: 3245 elif expr[0] == NOT:
3239 _get_expr_syms_rec(expr[1], res) 3246 _get_expr_syms_rec(expr[1], res)
3240 elif expr[0] == EQUAL or expr[0] == UNEQUAL: 3247 elif expr[0] == EQUAL or expr[0] == UNEQUAL:
3241 if isinstance(expr[1], Symbol): 3248 if isinstance(expr[1], Symbol):
3242 res.add(expr[1]) 3249 res.add(expr[1])
3243 if isinstance(expr[2], Symbol): 3250 if isinstance(expr[2], Symbol):
3244 res.add(expr[2]) 3251 res.add(expr[2])
3245 else: 3252 else:
3246 _internal_error("Internal error while fetching symbols from an " 3253 _internal_error("Internal error while fetching symbols from an "
3247 "expression with token stream {0}.".format(expr)) 3254 "expression with token stream {0}.".format(expr))
3248 3255
3249 def _get_expr_syms(expr): 3256 def _get_expr_syms(expr):
3250 """Returns the set() of symbols appearing in expr.""" 3257 """Returns the set() of symbols appearing in expr."""
3251 res = set() 3258 res = set()
3252 if expr is not None: 3259 if expr is not None:
3253 _get_expr_syms_rec(expr, res) 3260 _get_expr_syms_rec(expr, res)
3254 return res 3261 return res
3255 3262
3256 def _str_val(obj): 3263 def _str_val(obj):
3257 """Returns the value of obj as a string. If obj is not a string (constant 3264 """Returns the value of obj as a string. If obj is not a string (constant
3258 symbol), it must be a Symbol.""" 3265 symbol), it must be a Symbol."""
3259 return obj if isinstance(obj, str) else obj.get_value() 3266 return obj if isinstance(obj, str) else obj.get_value()
3260 3267
3261 def _make_block_conf(block, append_fn): 3268 def _make_block_conf(block, append_fn):
3262 """Returns a list of .config strings for a block (list) of items.""" 3269 """Returns a list of .config strings for a block (list) of items."""
3263 3270
3264 # Collect the substrings in a list and later use join() instead of += to 3271 # Collect the substrings in a list and later use join() instead of += to
3265 # build the final .config contents. With older Python versions, this yields 3272 # build the final .config contents. With older Python versions, this yields
3266 # linear instead of quadratic complexity. 3273 # linear instead of quadratic complexity.
3267 for item in block: 3274 for item in block:
3268 item._make_conf(append_fn) 3275 item._make_conf(append_fn)
3269 3276
3270 def _sym_str_string(sym_or_str): 3277 def _sym_str_string(sym_or_str):
3271 if isinstance(sym_or_str, str): 3278 if isinstance(sym_or_str, str):
3272 return '"' + sym_or_str + '"' 3279 return '"' + sym_or_str + '"'
3273 return sym_or_str.name 3280 return sym_or_str.name
3274 3281
3275 def _intersperse(lst, op): 3282 def _intersperse(lst, op):
3276 """_expr_to_str() helper. Gets the string representation of each expression 3283 """_expr_to_str() helper. Gets the string representation of each expression
3277 in lst and produces a list where op has been inserted between the 3284 in lst and produces a list where op has been inserted between the
3278 elements.""" 3285 elements."""
3279 if not lst: 3286 if not lst:
3280 return "" 3287 return ""
3281 3288
3282 res = [] 3289 res = []
3283 3290
3284 def handle_sub_expr(expr): 3291 def handle_sub_expr(expr):
3285 no_parens = isinstance(expr, (str, Symbol)) or \ 3292 no_parens = isinstance(expr, (str, Symbol)) or \
3286 expr[0] in (EQUAL, UNEQUAL) or \ 3293 expr[0] in (EQUAL, UNEQUAL) or \
3287 PRECEDENCE[op] <= PRECEDENCE[expr[0]] 3294 PRECEDENCE[op] <= PRECEDENCE[expr[0]]
3288 if not no_parens: 3295 if not no_parens:
3289 res.append("(") 3296 res.append("(")
3290 res.extend(_expr_to_str_rec(expr)) 3297 res.extend(_expr_to_str_rec(expr))
3291 if not no_parens: 3298 if not no_parens:
3292 res.append(")") 3299 res.append(")")
3293 3300
3294 op_str = OP_TO_STR[op] 3301 op_str = OP_TO_STR[op]
3295 3302
3296 handle_sub_expr(lst[0]) 3303 handle_sub_expr(lst[0])
3297 for expr in lst[1:]: 3304 for expr in lst[1:]:
3298 res.append(op_str) 3305 res.append(op_str)
3299 handle_sub_expr(expr) 3306 handle_sub_expr(expr)
3300 3307
3301 return res 3308 return res
3302 3309
3303 def _expr_to_str_rec(expr): 3310 def _expr_to_str_rec(expr):
3304 if expr is None: 3311 if expr is None:
3305 return [""] 3312 return [""]
3306 3313
3307 if isinstance(expr, (Symbol, str)): 3314 if isinstance(expr, (Symbol, str)):
3308 return [_sym_str_string(expr)] 3315 return [_sym_str_string(expr)]
3309 3316
3310 if expr[0] in (AND, OR): 3317 if expr[0] in (AND, OR):
3311 return _intersperse(expr[1], expr[0]) 3318 return _intersperse(expr[1], expr[0])
3312 3319
3313 if expr[0] == NOT: 3320 if expr[0] == NOT:
3314 need_parens = not isinstance(expr[1], (str, Symbol)) 3321 need_parens = not isinstance(expr[1], (str, Symbol))
3315 3322
3316 res = ["!"] 3323 res = ["!"]
3317 if need_parens: 3324 if need_parens:
3318 res.append("(") 3325 res.append("(")
3319 res.extend(_expr_to_str_rec(expr[1])) 3326 res.extend(_expr_to_str_rec(expr[1]))
3320 if need_parens: 3327 if need_parens:
3321 res.append(")") 3328 res.append(")")
3322 return res 3329 return res
3323 3330
3324 if expr[0] in (EQUAL, UNEQUAL): 3331 if expr[0] in (EQUAL, UNEQUAL):
3325 return [_sym_str_string(expr[1]), 3332 return [_sym_str_string(expr[1]),
3326 OP_TO_STR[expr[0]], 3333 OP_TO_STR[expr[0]],
3327 _sym_str_string(expr[2])] 3334 _sym_str_string(expr[2])]
3328 3335
3329 def _expr_to_str(expr): 3336 def _expr_to_str(expr):
3330 return "".join(_expr_to_str_rec(expr)) 3337 return "".join(_expr_to_str_rec(expr))
3331 3338
3332 def _indentation(line): 3339 def _indentation(line):
3333 """Returns the length of the line's leading whitespace, treating tab stops 3340 """Returns the length of the line's leading whitespace, treating tab stops
3334 as being spaced 8 characters apart.""" 3341 as being spaced 8 characters apart."""
3335 line = line.expandtabs() 3342 line = line.expandtabs()
3336 return len(line) - len(line.lstrip()) 3343 return len(line) - len(line.lstrip())
3337 3344
3338 def _deindent(line, indent): 3345 def _deindent(line, indent):
3339 """Deindent 'line' by 'indent' spaces.""" 3346 """Deindent 'line' by 'indent' spaces."""
3340 line = line.expandtabs() 3347 line = line.expandtabs()
3341 if len(line) <= indent: 3348 if len(line) <= indent:
3342 return line 3349 return line
3343 return line[indent:] 3350 return line[indent:]
3344 3351
3345 def _is_base_n(s, n): 3352 def _is_base_n(s, n):
3346 try: 3353 try:
3347 int(s, n) 3354 int(s, n)
3348 return True 3355 return True
3349 except ValueError: 3356 except ValueError:
3350 return False 3357 return False
3351 3358
3352 def _lines(*args): 3359 def _lines(*args):
3353 """Returns a string consisting of all arguments, with newlines inserted 3360 """Returns a string consisting of all arguments, with newlines inserted
3354 between them.""" 3361 between them."""
3355 return "\n".join(args) 3362 return "\n".join(args)
3356 3363
3357 def _comment(s): 3364 def _comment(s):
3358 """Returns a new string with "#" inserted before each line in 's'.""" 3365 """Returns a new string with "#" inserted before each line in 's'."""
3359 if not s: 3366 if not s:
3360 return "#" 3367 return "#"
3361 res = "".join(["#" + line for line in s.splitlines(True)]) 3368 res = "".join(["#" + line for line in s.splitlines(True)])
3362 if s.endswith("\n"): 3369 if s.endswith("\n"):
3363 return res + "#" 3370 return res + "#"
3364 return res 3371 return res
3365 3372
3366 def _clean_up_path(path): 3373 def _clean_up_path(path):
3367 """Strips an initial "./" and any trailing slashes from 'path'.""" 3374 """Strips an initial "./" and any trailing slashes from 'path'."""
3368 if path.startswith("./"): 3375 if path.startswith("./"):
3369 path = path[2:] 3376 path = path[2:]
3370 return path.rstrip("/") 3377 return path.rstrip("/")
3371 3378
3372 def _stderr_msg(msg, filename, linenr): 3379 def _build_msg(msg, filename, linenr):
3373 if filename is not None: 3380 if filename is not None:
3374 sys.stderr.write("{0}:{1}: ".format(_clean_up_path(filename), linenr)) 3381 msg = "{0}:{1}: ".format(_clean_up_path(filename), linenr) + msg
3375 sys.stderr.write(msg + "\n") 3382 return msg
3383
3384 def _stderr_msg(msg, filename, linenr):
3385 sys.stderr.write(_build_msg(msg, filename, linenr) + "\n")
3376 3386
3377 def _tokenization_error(s, filename, linenr): 3387 def _tokenization_error(s, filename, linenr):
3378 loc = "" if filename is None else "{0}:{1}: ".format(filename, linenr) 3388 loc = "" if filename is None else "{0}:{1}: ".format(filename, linenr)
3379 raise Kconfig_Syntax_Error("{0}Couldn't tokenize '{1}'" 3389 raise Kconfig_Syntax_Error("{0}Couldn't tokenize '{1}'"
3380 .format(loc, s.strip())) 3390 .format(loc, s.strip()))
3381 3391
3382 def _parse_error(s, msg, filename, linenr): 3392 def _parse_error(s, msg, filename, linenr):
3383 loc = "" if filename is None else "{0}:{1}: ".format(filename, linenr) 3393 loc = "" if filename is None else "{0}:{1}: ".format(filename, linenr)
3384 raise Kconfig_Syntax_Error("{0}Couldn't parse '{1}'{2}" 3394 raise Kconfig_Syntax_Error("{0}Couldn't parse '{1}'{2}"
3385 .format(loc, s.strip(), 3395 .format(loc, s.strip(),
3386 "." if msg is None else ": " + msg)) 3396 "." if msg is None else ": " + msg))
3387 3397
3388 def _internal_error(msg): 3398 def _internal_error(msg):
3389 raise Internal_Error(msg + 3399 raise Internal_Error(msg +
3390 "\nSorry! You may want to send an email to ulfalizer a.t Google's " 3400 "\nSorry! You may want to send an email to ulfalizer a.t Google's "
3391 "email service to tell me about this. Include the message above and the " 3401 "email service to tell me about this. Include the message above and the "
3392 "stack trace and describe what you were doing.") 3402 "stack trace and describe what you were doing.")
3393 3403
3394 # 3404 #
3395 # Internal global constants 3405 # Internal global constants
3396 # 3406 #
3397 3407
3398 # Tokens 3408 # Tokens
3399 (T_AND, T_OR, T_NOT, 3409 (T_AND, T_OR, T_NOT,
3400 T_OPEN_PAREN, T_CLOSE_PAREN, 3410 T_OPEN_PAREN, T_CLOSE_PAREN,
3401 T_EQUAL, T_UNEQUAL, 3411 T_EQUAL, T_UNEQUAL,
3402 T_MAINMENU, T_MENU, T_ENDMENU, 3412 T_MAINMENU, T_MENU, T_ENDMENU,
3403 T_SOURCE, T_CHOICE, T_ENDCHOICE, 3413 T_SOURCE, T_CHOICE, T_ENDCHOICE,
3404 T_COMMENT, T_CONFIG, T_MENUCONFIG, 3414 T_COMMENT, T_CONFIG, T_MENUCONFIG,
3405 T_HELP, T_IF, T_ENDIF, T_DEPENDS, T_ON, 3415 T_HELP, T_IF, T_ENDIF, T_DEPENDS, T_ON,
3406 T_OPTIONAL, T_PROMPT, T_DEFAULT, 3416 T_OPTIONAL, T_PROMPT, T_DEFAULT,
3407 T_BOOL, T_TRISTATE, T_HEX, T_INT, T_STRING, 3417 T_BOOL, T_TRISTATE, T_HEX, T_INT, T_STRING,
3408 T_DEF_BOOL, T_DEF_TRISTATE, 3418 T_DEF_BOOL, T_DEF_TRISTATE,
3409 T_SELECT, T_IMPLY, T_RANGE, T_OPTION, T_ALLNOCONFIG_Y, T_ENV, 3419 T_SELECT, T_IMPLY, T_RANGE, T_OPTION, T_ALLNOCONFIG_Y, T_ENV,
3410 T_DEFCONFIG_LIST, T_MODULES, T_VISIBLE) = range(40) 3420 T_DEFCONFIG_LIST, T_MODULES, T_VISIBLE) = range(40)
3411 3421
3412 # The leading underscore before the function assignments below prevent pydoc 3422 # The leading underscore before the function assignments below prevent pydoc
3413 # from listing them. The constants could be hidden too, but they're fairly 3423 # from listing them. The constants could be hidden too, but they're fairly
3414 # obviously internal anyway, so don't bother spamming the code. 3424 # obviously internal anyway, so don't bother spamming the code.
3415 3425
3416 # Keyword to token map. Note that the get() method is assigned directly as a 3426 # Keyword to token map. Note that the get() method is assigned directly as a
3417 # small optimization. 3427 # small optimization.
3418 _get_keyword = \ 3428 _get_keyword = \
3419 {"mainmenu": T_MAINMENU, "menu": T_MENU, "endmenu": T_ENDMENU, 3429 {"mainmenu": T_MAINMENU, "menu": T_MENU, "endmenu": T_ENDMENU,
3420 "endif": T_ENDIF, "endchoice": T_ENDCHOICE, "source": T_SOURCE, 3430 "endif": T_ENDIF, "endchoice": T_ENDCHOICE, "source": T_SOURCE,
3421 "choice": T_CHOICE, "config": T_CONFIG, "comment": T_COMMENT, 3431 "choice": T_CHOICE, "config": T_CONFIG, "comment": T_COMMENT,
3422 "menuconfig": T_MENUCONFIG, "help": T_HELP, "if": T_IF, 3432 "menuconfig": T_MENUCONFIG, "help": T_HELP, "if": T_IF,
3423 "depends": T_DEPENDS, "on": T_ON, "optional": T_OPTIONAL, 3433 "depends": T_DEPENDS, "on": T_ON, "optional": T_OPTIONAL,
3424 "prompt": T_PROMPT, "default": T_DEFAULT, "bool": T_BOOL, "boolean": T_BOOL, 3434 "prompt": T_PROMPT, "default": T_DEFAULT, "bool": T_BOOL, "boolean": T_BOOL,
3425 "tristate": T_TRISTATE, "int": T_INT, "hex": T_HEX, "def_bool": T_DEF_BOOL, 3435 "tristate": T_TRISTATE, "int": T_INT, "hex": T_HEX, "def_bool": T_DEF_BOOL,
3426 "def_tristate": T_DEF_TRISTATE, "string": T_STRING, "select": T_SELECT, 3436 "def_tristate": T_DEF_TRISTATE, "string": T_STRING, "select": T_SELECT,
3427 "imply": T_IMPLY, "range": T_RANGE, "option": T_OPTION, 3437 "imply": T_IMPLY, "range": T_RANGE, "option": T_OPTION,
3428 "allnoconfig_y": T_ALLNOCONFIG_Y, "env": T_ENV, 3438 "allnoconfig_y": T_ALLNOCONFIG_Y, "env": T_ENV,
3429 "defconfig_list": T_DEFCONFIG_LIST, "modules": T_MODULES, 3439 "defconfig_list": T_DEFCONFIG_LIST, "modules": T_MODULES,
3430 "visible": T_VISIBLE}.get 3440 "visible": T_VISIBLE}.get
3431 3441
3432 # Strings to use for True and False 3442 # Strings to use for True and False
3433 BOOL_STR = {False: "false", True: "true"} 3443 BOOL_STR = {False: "false", True: "true"}
3434 3444
3435 # Tokens after which identifier-like lexemes are treated as strings. T_CHOICE 3445 # Tokens after which identifier-like lexemes are treated as strings. T_CHOICE
3436 # is included to avoid symbols being registered for named choices. 3446 # is included to avoid symbols being registered for named choices.
3437 STRING_LEX = frozenset((T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING, T_CHOICE, 3447 STRING_LEX = frozenset((T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING, T_CHOICE,
3438 T_PROMPT, T_MENU, T_COMMENT, T_SOURCE, T_MAINMENU)) 3448 T_PROMPT, T_MENU, T_COMMENT, T_SOURCE, T_MAINMENU))
3439 3449
3440 # Matches the initial token on a line; see _tokenize(). Also eats trailing 3450 # Matches the initial token on a line; see _tokenize(). Also eats trailing
3441 # whitespace as an optimization. 3451 # whitespace as an optimization.
3442 _initial_token_re_match = re.compile(r"[^\w]*(\w+)\s*").match 3452 _initial_token_re_match = re.compile(r"[^\w]*(\w+)\s*").match
3443 3453
3444 # Matches an identifier/keyword optionally preceded by whitespace. Also eats 3454 # Matches an identifier/keyword optionally preceded by whitespace. Also eats
3445 # trailing whitespace as an optimization. 3455 # trailing whitespace as an optimization.
3446 _id_keyword_re_match = re.compile(r"\s*([\w./-]+)\s*").match 3456 _id_keyword_re_match = re.compile(r"\s*([\w./-]+)\s*").match
3447 3457
3448 # Regular expressions for parsing .config files 3458 # Regular expressions for parsing .config files
3449 _set_re_match = re.compile(r"CONFIG_(\w+)=(.*)").match 3459 _set_re_match = re.compile(r"CONFIG_(\w+)=(.*)").match
3450 _unset_re_match = re.compile(r"# CONFIG_(\w+) is not set").match 3460 _unset_re_match = re.compile(r"# CONFIG_(\w+) is not set").match
3451 3461
3452 # Regular expression for finding $-references to symbols in strings 3462 # Regular expression for finding $-references to symbols in strings
3453 _sym_ref_re_search = re.compile(r"\$[A-Za-z0-9_]+").search 3463 _sym_ref_re_search = re.compile(r"\$[A-Za-z0-9_]+").search
3454 3464
3455 # Integers representing symbol types 3465 # Integers representing symbol types
3456 UNKNOWN, BOOL, TRISTATE, STRING, HEX, INT = range(6) 3466 UNKNOWN, BOOL, TRISTATE, STRING, HEX, INT = range(6)
3457 3467
3458 # Strings to use for types 3468 # Strings to use for types
3459 TYPENAME = {UNKNOWN: "unknown", BOOL: "bool", TRISTATE: "tristate", 3469 TYPENAME = {UNKNOWN: "unknown", BOOL: "bool", TRISTATE: "tristate",
3460 STRING: "string", HEX: "hex", INT: "int"} 3470 STRING: "string", HEX: "hex", INT: "int"}
3461 3471
3462 # Token to type mapping 3472 # Token to type mapping
3463 TOKEN_TO_TYPE = {T_BOOL: BOOL, T_TRISTATE: TRISTATE, T_STRING: STRING, 3473 TOKEN_TO_TYPE = {T_BOOL: BOOL, T_TRISTATE: TRISTATE, T_STRING: STRING,
3464 T_INT: INT, T_HEX: HEX} 3474 T_INT: INT, T_HEX: HEX}
3465 3475
3466 # Default values for symbols of different types (the value the symbol gets if 3476 # Default values for symbols of different types (the value the symbol gets if
3467 # it is not assigned a user value and none of its 'default' clauses kick in) 3477 # it is not assigned a user value and none of its 'default' clauses kick in)
3468 DEFAULT_VALUE = {BOOL: "n", TRISTATE: "n", STRING: "", INT: "", HEX: ""} 3478 DEFAULT_VALUE = {BOOL: "n", TRISTATE: "n", STRING: "", INT: "", HEX: ""}
3469 3479
3470 # Indicates that no item is selected in a choice statement 3480 # Indicates that no item is selected in a choice statement
3471 NO_SELECTION = 0 3481 NO_SELECTION = 0
3472 3482
3473 # Integers representing expression types 3483 # Integers representing expression types
3474 AND, OR, NOT, EQUAL, UNEQUAL = range(5) 3484 AND, OR, NOT, EQUAL, UNEQUAL = range(5)
3475 3485
3476 # Map from tristate values to integers 3486 # Map from tristate values to integers
3477 TRI_TO_INT = {"n": 0, "m": 1, "y": 2} 3487 TRI_TO_INT = {"n": 0, "m": 1, "y": 2}
3478 3488
3479 # Printing-related stuff 3489 # Printing-related stuff
3480 3490
3481 OP_TO_STR = {AND: " && ", OR: " || ", EQUAL: " = ", UNEQUAL: " != "} 3491 OP_TO_STR = {AND: " && ", OR: " || ", EQUAL: " = ", UNEQUAL: " != "}
3482 PRECEDENCE = {OR: 0, AND: 1, NOT: 2} 3492 PRECEDENCE = {OR: 0, AND: 1, NOT: 2}
3483 3493
tools/genboardscfg.py
1 #!/usr/bin/env python2 1 #!/usr/bin/env python2
2 # 2 #
3 # Author: Masahiro Yamada <yamada.m@jp.panasonic.com> 3 # Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
4 # 4 #
5 # SPDX-License-Identifier: GPL-2.0+ 5 # SPDX-License-Identifier: GPL-2.0+
6 # 6 #
7 7
8 """ 8 """
9 Converter from Kconfig and MAINTAINERS to a board database. 9 Converter from Kconfig and MAINTAINERS to a board database.
10 10
11 Run 'tools/genboardscfg.py' to create a board database. 11 Run 'tools/genboardscfg.py' to create a board database.
12 12
13 Run 'tools/genboardscfg.py -h' for available options. 13 Run 'tools/genboardscfg.py -h' for available options.
14 14
15 Python 2.6 or later, but not Python 3.x is necessary to run this script. 15 Python 2.6 or later, but not Python 3.x is necessary to run this script.
16 """ 16 """
17 17
18 import errno 18 import errno
19 import fnmatch 19 import fnmatch
20 import glob 20 import glob
21 import multiprocessing 21 import multiprocessing
22 import optparse 22 import optparse
23 import os 23 import os
24 import sys 24 import sys
25 import tempfile 25 import tempfile
26 import time 26 import time
27 27
28 sys.path.append(os.path.join(os.path.dirname(__file__), 'buildman')) 28 sys.path.append(os.path.join(os.path.dirname(__file__), 'buildman'))
29 import kconfiglib 29 import kconfiglib
30 30
31 ### constant variables ### 31 ### constant variables ###
32 OUTPUT_FILE = 'boards.cfg' 32 OUTPUT_FILE = 'boards.cfg'
33 CONFIG_DIR = 'configs' 33 CONFIG_DIR = 'configs'
34 SLEEP_TIME = 0.03 34 SLEEP_TIME = 0.03
35 COMMENT_BLOCK = '''# 35 COMMENT_BLOCK = '''#
36 # List of boards 36 # List of boards
37 # Automatically generated by %s: don't edit 37 # Automatically generated by %s: don't edit
38 # 38 #
39 # Status, Arch, CPU, SoC, Vendor, Board, Target, Options, Maintainers 39 # Status, Arch, CPU, SoC, Vendor, Board, Target, Options, Maintainers
40 40
41 ''' % __file__ 41 ''' % __file__
42 42
43 ### helper functions ### 43 ### helper functions ###
44 def try_remove(f): 44 def try_remove(f):
45 """Remove a file ignoring 'No such file or directory' error.""" 45 """Remove a file ignoring 'No such file or directory' error."""
46 try: 46 try:
47 os.remove(f) 47 os.remove(f)
48 except OSError as exception: 48 except OSError as exception:
49 # Ignore 'No such file or directory' error 49 # Ignore 'No such file or directory' error
50 if exception.errno != errno.ENOENT: 50 if exception.errno != errno.ENOENT:
51 raise 51 raise
52 52
53 def check_top_directory(): 53 def check_top_directory():
54 """Exit if we are not at the top of source directory.""" 54 """Exit if we are not at the top of source directory."""
55 for f in ('README', 'Licenses'): 55 for f in ('README', 'Licenses'):
56 if not os.path.exists(f): 56 if not os.path.exists(f):
57 sys.exit('Please run at the top of source directory.') 57 sys.exit('Please run at the top of source directory.')
58 58
59 def output_is_new(output): 59 def output_is_new(output):
60 """Check if the output file is up to date. 60 """Check if the output file is up to date.
61 61
62 Returns: 62 Returns:
63 True if the given output file exists and is newer than any of 63 True if the given output file exists and is newer than any of
64 *_defconfig, MAINTAINERS and Kconfig*. False otherwise. 64 *_defconfig, MAINTAINERS and Kconfig*. False otherwise.
65 """ 65 """
66 try: 66 try:
67 ctime = os.path.getctime(output) 67 ctime = os.path.getctime(output)
68 except OSError as exception: 68 except OSError as exception:
69 if exception.errno == errno.ENOENT: 69 if exception.errno == errno.ENOENT:
70 # return False on 'No such file or directory' error 70 # return False on 'No such file or directory' error
71 return False 71 return False
72 else: 72 else:
73 raise 73 raise
74 74
75 for (dirpath, dirnames, filenames) in os.walk(CONFIG_DIR): 75 for (dirpath, dirnames, filenames) in os.walk(CONFIG_DIR):
76 for filename in fnmatch.filter(filenames, '*_defconfig'): 76 for filename in fnmatch.filter(filenames, '*_defconfig'):
77 if fnmatch.fnmatch(filename, '.*'): 77 if fnmatch.fnmatch(filename, '.*'):
78 continue 78 continue
79 filepath = os.path.join(dirpath, filename) 79 filepath = os.path.join(dirpath, filename)
80 if ctime < os.path.getctime(filepath): 80 if ctime < os.path.getctime(filepath):
81 return False 81 return False
82 82
83 for (dirpath, dirnames, filenames) in os.walk('.'): 83 for (dirpath, dirnames, filenames) in os.walk('.'):
84 for filename in filenames: 84 for filename in filenames:
85 if (fnmatch.fnmatch(filename, '*~') or 85 if (fnmatch.fnmatch(filename, '*~') or
86 not fnmatch.fnmatch(filename, 'Kconfig*') and 86 not fnmatch.fnmatch(filename, 'Kconfig*') and
87 not filename == 'MAINTAINERS'): 87 not filename == 'MAINTAINERS'):
88 continue 88 continue
89 filepath = os.path.join(dirpath, filename) 89 filepath = os.path.join(dirpath, filename)
90 if ctime < os.path.getctime(filepath): 90 if ctime < os.path.getctime(filepath):
91 return False 91 return False
92 92
93 # Detect a board that has been removed since the current board database 93 # Detect a board that has been removed since the current board database
94 # was generated 94 # was generated
95 with open(output) as f: 95 with open(output) as f:
96 for line in f: 96 for line in f:
97 if line[0] == '#' or line == '\n': 97 if line[0] == '#' or line == '\n':
98 continue 98 continue
99 defconfig = line.split()[6] + '_defconfig' 99 defconfig = line.split()[6] + '_defconfig'
100 if not os.path.exists(os.path.join(CONFIG_DIR, defconfig)): 100 if not os.path.exists(os.path.join(CONFIG_DIR, defconfig)):
101 return False 101 return False
102 102
103 return True 103 return True
104 104
105 ### classes ### 105 ### classes ###
106 class KconfigScanner: 106 class KconfigScanner:
107 107
108 """Kconfig scanner.""" 108 """Kconfig scanner."""
109 109
110 ### constant variable only used in this class ### 110 ### constant variable only used in this class ###
111 _SYMBOL_TABLE = { 111 _SYMBOL_TABLE = {
112 'arch' : 'SYS_ARCH', 112 'arch' : 'SYS_ARCH',
113 'cpu' : 'SYS_CPU', 113 'cpu' : 'SYS_CPU',
114 'soc' : 'SYS_SOC', 114 'soc' : 'SYS_SOC',
115 'vendor' : 'SYS_VENDOR', 115 'vendor' : 'SYS_VENDOR',
116 'board' : 'SYS_BOARD', 116 'board' : 'SYS_BOARD',
117 'config' : 'SYS_CONFIG_NAME', 117 'config' : 'SYS_CONFIG_NAME',
118 'options' : 'SYS_EXTRA_OPTIONS' 118 'options' : 'SYS_EXTRA_OPTIONS'
119 } 119 }
120 120
121 def __init__(self): 121 def __init__(self):
122 """Scan all the Kconfig files and create a Config object.""" 122 """Scan all the Kconfig files and create a Config object."""
123 # Define environment variables referenced from Kconfig 123 # Define environment variables referenced from Kconfig
124 os.environ['srctree'] = os.getcwd() 124 os.environ['srctree'] = os.getcwd()
125 os.environ['UBOOTVERSION'] = 'dummy' 125 os.environ['UBOOTVERSION'] = 'dummy'
126 os.environ['KCONFIG_OBJDIR'] = '' 126 os.environ['KCONFIG_OBJDIR'] = ''
127 self._conf = kconfiglib.Config() 127 self._conf = kconfiglib.Config(print_warnings=False)
128 128
129 def __del__(self): 129 def __del__(self):
130 """Delete a leftover temporary file before exit. 130 """Delete a leftover temporary file before exit.
131 131
132 The scan() method of this class creates a temporay file and deletes 132 The scan() method of this class creates a temporay file and deletes
133 it on success. If scan() method throws an exception on the way, 133 it on success. If scan() method throws an exception on the way,
134 the temporary file might be left over. In that case, it should be 134 the temporary file might be left over. In that case, it should be
135 deleted in this destructor. 135 deleted in this destructor.
136 """ 136 """
137 if hasattr(self, '_tmpfile') and self._tmpfile: 137 if hasattr(self, '_tmpfile') and self._tmpfile:
138 try_remove(self._tmpfile) 138 try_remove(self._tmpfile)
139 139
140 def scan(self, defconfig): 140 def scan(self, defconfig):
141 """Load a defconfig file to obtain board parameters. 141 """Load a defconfig file to obtain board parameters.
142 142
143 Arguments: 143 Arguments:
144 defconfig: path to the defconfig file to be processed 144 defconfig: path to the defconfig file to be processed
145 145
146 Returns: 146 Returns:
147 A dictionary of board parameters. It has a form of: 147 A dictionary of board parameters. It has a form of:
148 { 148 {
149 'arch': <arch_name>, 149 'arch': <arch_name>,
150 'cpu': <cpu_name>, 150 'cpu': <cpu_name>,
151 'soc': <soc_name>, 151 'soc': <soc_name>,
152 'vendor': <vendor_name>, 152 'vendor': <vendor_name>,
153 'board': <board_name>, 153 'board': <board_name>,
154 'target': <target_name>, 154 'target': <target_name>,
155 'config': <config_header_name>, 155 'config': <config_header_name>,
156 'options': <extra_options> 156 'options': <extra_options>
157 } 157 }
158 """ 158 """
159 # strip special prefixes and save it in a temporary file 159 # strip special prefixes and save it in a temporary file
160 fd, self._tmpfile = tempfile.mkstemp() 160 fd, self._tmpfile = tempfile.mkstemp()
161 with os.fdopen(fd, 'w') as f: 161 with os.fdopen(fd, 'w') as f:
162 for line in open(defconfig): 162 for line in open(defconfig):
163 colon = line.find(':CONFIG_') 163 colon = line.find(':CONFIG_')
164 if colon == -1: 164 if colon == -1:
165 f.write(line) 165 f.write(line)
166 else: 166 else:
167 f.write(line[colon + 1:]) 167 f.write(line[colon + 1:])
168 168
169 self._conf.load_config(self._tmpfile) 169 warnings = self._conf.load_config(self._tmpfile)
170 if warnings:
171 for warning in warnings:
172 print '%s: %s' % (defconfig, warning)
170 173
171 try_remove(self._tmpfile) 174 try_remove(self._tmpfile)
172 self._tmpfile = None 175 self._tmpfile = None
173 176
174 params = {} 177 params = {}
175 178
176 # Get the value of CONFIG_SYS_ARCH, CONFIG_SYS_CPU, ... etc. 179 # Get the value of CONFIG_SYS_ARCH, CONFIG_SYS_CPU, ... etc.
177 # Set '-' if the value is empty. 180 # Set '-' if the value is empty.
178 for key, symbol in self._SYMBOL_TABLE.items(): 181 for key, symbol in self._SYMBOL_TABLE.items():
179 value = self._conf.get_symbol(symbol).get_value() 182 value = self._conf.get_symbol(symbol).get_value()
180 if value: 183 if value:
181 params[key] = value 184 params[key] = value
182 else: 185 else:
183 params[key] = '-' 186 params[key] = '-'
184 187
185 defconfig = os.path.basename(defconfig) 188 defconfig = os.path.basename(defconfig)
186 params['target'], match, rear = defconfig.partition('_defconfig') 189 params['target'], match, rear = defconfig.partition('_defconfig')
187 assert match and not rear, '%s : invalid defconfig' % defconfig 190 assert match and not rear, '%s : invalid defconfig' % defconfig
188 191
189 # fix-up for aarch64 192 # fix-up for aarch64
190 if params['arch'] == 'arm' and params['cpu'] == 'armv8': 193 if params['arch'] == 'arm' and params['cpu'] == 'armv8':
191 params['arch'] = 'aarch64' 194 params['arch'] = 'aarch64'
192 195
193 # fix-up options field. It should have the form: 196 # fix-up options field. It should have the form:
194 # <config name>[:comma separated config options] 197 # <config name>[:comma separated config options]
195 if params['options'] != '-': 198 if params['options'] != '-':
196 params['options'] = params['config'] + ':' + \ 199 params['options'] = params['config'] + ':' + \
197 params['options'].replace(r'\"', '"') 200 params['options'].replace(r'\"', '"')
198 elif params['config'] != params['target']: 201 elif params['config'] != params['target']:
199 params['options'] = params['config'] 202 params['options'] = params['config']
200 203
201 return params 204 return params
202 205
203 def scan_defconfigs_for_multiprocess(queue, defconfigs): 206 def scan_defconfigs_for_multiprocess(queue, defconfigs):
204 """Scan defconfig files and queue their board parameters 207 """Scan defconfig files and queue their board parameters
205 208
206 This function is intended to be passed to 209 This function is intended to be passed to
207 multiprocessing.Process() constructor. 210 multiprocessing.Process() constructor.
208 211
209 Arguments: 212 Arguments:
210 queue: An instance of multiprocessing.Queue(). 213 queue: An instance of multiprocessing.Queue().
211 The resulting board parameters are written into it. 214 The resulting board parameters are written into it.
212 defconfigs: A sequence of defconfig files to be scanned. 215 defconfigs: A sequence of defconfig files to be scanned.
213 """ 216 """
214 kconf_scanner = KconfigScanner() 217 kconf_scanner = KconfigScanner()
215 for defconfig in defconfigs: 218 for defconfig in defconfigs:
216 queue.put(kconf_scanner.scan(defconfig)) 219 queue.put(kconf_scanner.scan(defconfig))
217 220
218 def read_queues(queues, params_list): 221 def read_queues(queues, params_list):
219 """Read the queues and append the data to the paramers list""" 222 """Read the queues and append the data to the paramers list"""
220 for q in queues: 223 for q in queues:
221 while not q.empty(): 224 while not q.empty():
222 params_list.append(q.get()) 225 params_list.append(q.get())
223 226
224 def scan_defconfigs(jobs=1): 227 def scan_defconfigs(jobs=1):
225 """Collect board parameters for all defconfig files. 228 """Collect board parameters for all defconfig files.
226 229
227 This function invokes multiple processes for faster processing. 230 This function invokes multiple processes for faster processing.
228 231
229 Arguments: 232 Arguments:
230 jobs: The number of jobs to run simultaneously 233 jobs: The number of jobs to run simultaneously
231 """ 234 """
232 all_defconfigs = [] 235 all_defconfigs = []
233 for (dirpath, dirnames, filenames) in os.walk(CONFIG_DIR): 236 for (dirpath, dirnames, filenames) in os.walk(CONFIG_DIR):
234 for filename in fnmatch.filter(filenames, '*_defconfig'): 237 for filename in fnmatch.filter(filenames, '*_defconfig'):
235 if fnmatch.fnmatch(filename, '.*'): 238 if fnmatch.fnmatch(filename, '.*'):
236 continue 239 continue
237 all_defconfigs.append(os.path.join(dirpath, filename)) 240 all_defconfigs.append(os.path.join(dirpath, filename))
238 241
239 total_boards = len(all_defconfigs) 242 total_boards = len(all_defconfigs)
240 processes = [] 243 processes = []
241 queues = [] 244 queues = []
242 for i in range(jobs): 245 for i in range(jobs):
243 defconfigs = all_defconfigs[total_boards * i / jobs : 246 defconfigs = all_defconfigs[total_boards * i / jobs :
244 total_boards * (i + 1) / jobs] 247 total_boards * (i + 1) / jobs]
245 q = multiprocessing.Queue(maxsize=-1) 248 q = multiprocessing.Queue(maxsize=-1)
246 p = multiprocessing.Process(target=scan_defconfigs_for_multiprocess, 249 p = multiprocessing.Process(target=scan_defconfigs_for_multiprocess,
247 args=(q, defconfigs)) 250 args=(q, defconfigs))
248 p.start() 251 p.start()
249 processes.append(p) 252 processes.append(p)
250 queues.append(q) 253 queues.append(q)
251 254
252 # The resulting data should be accumulated to this list 255 # The resulting data should be accumulated to this list
253 params_list = [] 256 params_list = []
254 257
255 # Data in the queues should be retrieved preriodically. 258 # Data in the queues should be retrieved preriodically.
256 # Otherwise, the queues would become full and subprocesses would get stuck. 259 # Otherwise, the queues would become full and subprocesses would get stuck.
257 while any([p.is_alive() for p in processes]): 260 while any([p.is_alive() for p in processes]):
258 read_queues(queues, params_list) 261 read_queues(queues, params_list)
259 # sleep for a while until the queues are filled 262 # sleep for a while until the queues are filled
260 time.sleep(SLEEP_TIME) 263 time.sleep(SLEEP_TIME)
261 264
262 # Joining subprocesses just in case 265 # Joining subprocesses just in case
263 # (All subprocesses should already have been finished) 266 # (All subprocesses should already have been finished)
264 for p in processes: 267 for p in processes:
265 p.join() 268 p.join()
266 269
267 # retrieve leftover data 270 # retrieve leftover data
268 read_queues(queues, params_list) 271 read_queues(queues, params_list)
269 272
270 return params_list 273 return params_list
271 274
272 class MaintainersDatabase: 275 class MaintainersDatabase:
273 276
274 """The database of board status and maintainers.""" 277 """The database of board status and maintainers."""
275 278
276 def __init__(self): 279 def __init__(self):
277 """Create an empty database.""" 280 """Create an empty database."""
278 self.database = {} 281 self.database = {}
279 282
280 def get_status(self, target): 283 def get_status(self, target):
281 """Return the status of the given board. 284 """Return the status of the given board.
282 285
283 The board status is generally either 'Active' or 'Orphan'. 286 The board status is generally either 'Active' or 'Orphan'.
284 Display a warning message and return '-' if status information 287 Display a warning message and return '-' if status information
285 is not found. 288 is not found.
286 289
287 Returns: 290 Returns:
288 'Active', 'Orphan' or '-'. 291 'Active', 'Orphan' or '-'.
289 """ 292 """
290 if not target in self.database: 293 if not target in self.database:
291 print >> sys.stderr, "WARNING: no status info for '%s'" % target 294 print >> sys.stderr, "WARNING: no status info for '%s'" % target
292 return '-' 295 return '-'
293 296
294 tmp = self.database[target][0] 297 tmp = self.database[target][0]
295 if tmp.startswith('Maintained'): 298 if tmp.startswith('Maintained'):
296 return 'Active' 299 return 'Active'
297 elif tmp.startswith('Supported'): 300 elif tmp.startswith('Supported'):
298 return 'Active' 301 return 'Active'
299 elif tmp.startswith('Orphan'): 302 elif tmp.startswith('Orphan'):
300 return 'Orphan' 303 return 'Orphan'
301 else: 304 else:
302 print >> sys.stderr, ("WARNING: %s: unknown status for '%s'" % 305 print >> sys.stderr, ("WARNING: %s: unknown status for '%s'" %
303 (tmp, target)) 306 (tmp, target))
304 return '-' 307 return '-'
305 308
306 def get_maintainers(self, target): 309 def get_maintainers(self, target):
307 """Return the maintainers of the given board. 310 """Return the maintainers of the given board.
308 311
309 Returns: 312 Returns:
310 Maintainers of the board. If the board has two or more maintainers, 313 Maintainers of the board. If the board has two or more maintainers,
311 they are separated with colons. 314 they are separated with colons.
312 """ 315 """
313 if not target in self.database: 316 if not target in self.database:
314 print >> sys.stderr, "WARNING: no maintainers for '%s'" % target 317 print >> sys.stderr, "WARNING: no maintainers for '%s'" % target
315 return '' 318 return ''
316 319
317 return ':'.join(self.database[target][1]) 320 return ':'.join(self.database[target][1])
318 321
319 def parse_file(self, file): 322 def parse_file(self, file):
320 """Parse a MAINTAINERS file. 323 """Parse a MAINTAINERS file.
321 324
322 Parse a MAINTAINERS file and accumulates board status and 325 Parse a MAINTAINERS file and accumulates board status and
323 maintainers information. 326 maintainers information.
324 327
325 Arguments: 328 Arguments:
326 file: MAINTAINERS file to be parsed 329 file: MAINTAINERS file to be parsed
327 """ 330 """
328 targets = [] 331 targets = []
329 maintainers = [] 332 maintainers = []
330 status = '-' 333 status = '-'
331 for line in open(file): 334 for line in open(file):
332 # Check also commented maintainers 335 # Check also commented maintainers
333 if line[:3] == '#M:': 336 if line[:3] == '#M:':
334 line = line[1:] 337 line = line[1:]
335 tag, rest = line[:2], line[2:].strip() 338 tag, rest = line[:2], line[2:].strip()
336 if tag == 'M:': 339 if tag == 'M:':
337 maintainers.append(rest) 340 maintainers.append(rest)
338 elif tag == 'F:': 341 elif tag == 'F:':
339 # expand wildcard and filter by 'configs/*_defconfig' 342 # expand wildcard and filter by 'configs/*_defconfig'
340 for f in glob.glob(rest): 343 for f in glob.glob(rest):
341 front, match, rear = f.partition('configs/') 344 front, match, rear = f.partition('configs/')
342 if not front and match: 345 if not front and match:
343 front, match, rear = rear.rpartition('_defconfig') 346 front, match, rear = rear.rpartition('_defconfig')
344 if match and not rear: 347 if match and not rear:
345 targets.append(front) 348 targets.append(front)
346 elif tag == 'S:': 349 elif tag == 'S:':
347 status = rest 350 status = rest
348 elif line == '\n': 351 elif line == '\n':
349 for target in targets: 352 for target in targets:
350 self.database[target] = (status, maintainers) 353 self.database[target] = (status, maintainers)
351 targets = [] 354 targets = []
352 maintainers = [] 355 maintainers = []
353 status = '-' 356 status = '-'
354 if targets: 357 if targets:
355 for target in targets: 358 for target in targets:
356 self.database[target] = (status, maintainers) 359 self.database[target] = (status, maintainers)
357 360
358 def insert_maintainers_info(params_list): 361 def insert_maintainers_info(params_list):
359 """Add Status and Maintainers information to the board parameters list. 362 """Add Status and Maintainers information to the board parameters list.
360 363
361 Arguments: 364 Arguments:
362 params_list: A list of the board parameters 365 params_list: A list of the board parameters
363 """ 366 """
364 database = MaintainersDatabase() 367 database = MaintainersDatabase()
365 for (dirpath, dirnames, filenames) in os.walk('.'): 368 for (dirpath, dirnames, filenames) in os.walk('.'):
366 if 'MAINTAINERS' in filenames: 369 if 'MAINTAINERS' in filenames:
367 database.parse_file(os.path.join(dirpath, 'MAINTAINERS')) 370 database.parse_file(os.path.join(dirpath, 'MAINTAINERS'))
368 371
369 for i, params in enumerate(params_list): 372 for i, params in enumerate(params_list):
370 target = params['target'] 373 target = params['target']
371 params['status'] = database.get_status(target) 374 params['status'] = database.get_status(target)
372 params['maintainers'] = database.get_maintainers(target) 375 params['maintainers'] = database.get_maintainers(target)
373 params_list[i] = params 376 params_list[i] = params
374 377
375 def format_and_output(params_list, output): 378 def format_and_output(params_list, output):
376 """Write board parameters into a file. 379 """Write board parameters into a file.
377 380
378 Columnate the board parameters, sort lines alphabetically, 381 Columnate the board parameters, sort lines alphabetically,
379 and then write them to a file. 382 and then write them to a file.
380 383
381 Arguments: 384 Arguments:
382 params_list: The list of board parameters 385 params_list: The list of board parameters
383 output: The path to the output file 386 output: The path to the output file
384 """ 387 """
385 FIELDS = ('status', 'arch', 'cpu', 'soc', 'vendor', 'board', 'target', 388 FIELDS = ('status', 'arch', 'cpu', 'soc', 'vendor', 'board', 'target',
386 'options', 'maintainers') 389 'options', 'maintainers')
387 390
388 # First, decide the width of each column 391 # First, decide the width of each column
389 max_length = dict([ (f, 0) for f in FIELDS]) 392 max_length = dict([ (f, 0) for f in FIELDS])
390 for params in params_list: 393 for params in params_list:
391 for f in FIELDS: 394 for f in FIELDS:
392 max_length[f] = max(max_length[f], len(params[f])) 395 max_length[f] = max(max_length[f], len(params[f]))
393 396
394 output_lines = [] 397 output_lines = []
395 for params in params_list: 398 for params in params_list:
396 line = '' 399 line = ''
397 for f in FIELDS: 400 for f in FIELDS:
398 # insert two spaces between fields like column -t would 401 # insert two spaces between fields like column -t would
399 line += ' ' + params[f].ljust(max_length[f]) 402 line += ' ' + params[f].ljust(max_length[f])
400 output_lines.append(line.strip()) 403 output_lines.append(line.strip())
401 404
402 # ignore case when sorting 405 # ignore case when sorting
403 output_lines.sort(key=str.lower) 406 output_lines.sort(key=str.lower)
404 407
405 with open(output, 'w') as f: 408 with open(output, 'w') as f:
406 f.write(COMMENT_BLOCK + '\n'.join(output_lines) + '\n') 409 f.write(COMMENT_BLOCK + '\n'.join(output_lines) + '\n')
407 410
408 def gen_boards_cfg(output, jobs=1, force=False): 411 def gen_boards_cfg(output, jobs=1, force=False):
409 """Generate a board database file. 412 """Generate a board database file.
410 413
411 Arguments: 414 Arguments:
412 output: The name of the output file 415 output: The name of the output file
413 jobs: The number of jobs to run simultaneously 416 jobs: The number of jobs to run simultaneously
414 force: Force to generate the output even if it is new 417 force: Force to generate the output even if it is new
415 """ 418 """
416 check_top_directory() 419 check_top_directory()
417 420
418 if not force and output_is_new(output): 421 if not force and output_is_new(output):
419 print "%s is up to date. Nothing to do." % output 422 print "%s is up to date. Nothing to do." % output
420 sys.exit(0) 423 sys.exit(0)
421 424
422 params_list = scan_defconfigs(jobs) 425 params_list = scan_defconfigs(jobs)
423 insert_maintainers_info(params_list) 426 insert_maintainers_info(params_list)
424 format_and_output(params_list, output) 427 format_and_output(params_list, output)
425 428
426 def main(): 429 def main():
427 try: 430 try:
428 cpu_count = multiprocessing.cpu_count() 431 cpu_count = multiprocessing.cpu_count()
429 except NotImplementedError: 432 except NotImplementedError:
430 cpu_count = 1 433 cpu_count = 1
431 434
432 parser = optparse.OptionParser() 435 parser = optparse.OptionParser()
433 # Add options here 436 # Add options here
434 parser.add_option('-f', '--force', action="store_true", default=False, 437 parser.add_option('-f', '--force', action="store_true", default=False,
435 help='regenerate the output even if it is new') 438 help='regenerate the output even if it is new')
436 parser.add_option('-j', '--jobs', type='int', default=cpu_count, 439 parser.add_option('-j', '--jobs', type='int', default=cpu_count,
437 help='the number of jobs to run simultaneously') 440 help='the number of jobs to run simultaneously')
438 parser.add_option('-o', '--output', default=OUTPUT_FILE, 441 parser.add_option('-o', '--output', default=OUTPUT_FILE,
439 help='output file [default=%s]' % OUTPUT_FILE) 442 help='output file [default=%s]' % OUTPUT_FILE)
440 (options, args) = parser.parse_args() 443 (options, args) = parser.parse_args()
441 444
442 gen_boards_cfg(options.output, jobs=options.jobs, force=options.force) 445 gen_boards_cfg(options.output, jobs=options.jobs, force=options.force)
443 446
444 if __name__ == '__main__': 447 if __name__ == '__main__':
445 main() 448 main()
446 449