minikconfig: implement allnoconfig and defconfig modes

Apart from defconfig (which is a no-op),
allyesconfig/allnoconfig/randcondfig can be implemented simply by ignoring
the RHS of assignments and "default" statements.  The RHS is replaced
respectively by "true", "false" or a random value.

However, allyesconfig and randconfig do not quite work, because all the
files for hw/ARCH/Kconfig are sourced and therefore you could end up
enabling some ARM boards in x86 or things like that.  This is left for
future work, but I am leaving it in to help debugging minikconf itself.

allnoconfig mode is tied to a new configure option, --without-default-devices.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/scripts/minikconf.py b/scripts/minikconf.py
index 6bedc57..5421db0 100644
--- a/scripts/minikconf.py
+++ b/scripts/minikconf.py
@@ -14,9 +14,11 @@
 import os
 import sys
 import re
+import random
 
 __all__ = [ 'KconfigDataError', 'KconfigParserError',
-            'KconfigData', 'KconfigParser' ]
+            'KconfigData', 'KconfigParser' ,
+            'defconfig', 'allyesconfig', 'allnoconfig', 'randconfig' ]
 
 def debug_print(*args):
     #print('# ' + (' '.join(str(x) for x in args)))
@@ -39,6 +41,11 @@
     def __str__(self):
         return self.msg
 
+allyesconfig = lambda x: True
+allnoconfig = lambda x: False
+defconfig = lambda x: x
+randconfig = lambda x: random.randint(0, 1) == 1
+
 class KconfigData:
     class Expr:
         def __and__(self, rhs):
@@ -192,7 +199,8 @@
             if self.cond.evaluate():
                 self.dest.set_value(True, self)
 
-    def __init__(self):
+    def __init__(self, value_mangler=defconfig):
+        self.value_mangler = value_mangler
         self.previously_included = []
         self.incl_info = None
         self.defined_vars = set()
@@ -272,6 +280,7 @@
         self.clauses.append(KconfigData.AssignmentClause(var, val))
 
     def do_default(self, var, val, cond=None):
+        val = self.value_mangler(val)
         self.clauses.append(KconfigData.DefaultClause(var, val, cond))
 
     def do_depends_on(self, var, expr):
@@ -328,9 +337,10 @@
         return "%s: %s" % (self.loc, self.msg)
 
 class KconfigParser:
+
     @classmethod
-    def parse(self, fp):
-        data = KconfigData()
+    def parse(self, fp, mode=None):
+        data = KconfigData(mode or KconfigParser.defconfig)
         parser = KconfigParser(data)
         parser.parse_file(fp)
         return data
@@ -653,11 +663,30 @@
 
 if __name__ == '__main__':
     argv = sys.argv
+    mode = defconfig
+    if len(sys.argv) > 1:
+        if argv[1] == '--defconfig':
+            del argv[1]
+        elif argv[1] == '--randconfig':
+            random.seed()
+            mode = randconfig
+            del argv[1]
+        elif argv[1] == '--allyesconfig':
+            mode = allyesconfig
+            del argv[1]
+        elif argv[1] == '--allnoconfig':
+            mode = allnoconfig
+            del argv[1]
+
     if len(argv) == 1:
         print ("%s: at least one argument is required" % argv[0], file=sys.stderr)
         sys.exit(1)
 
-    data = KconfigData()
+    if argv[1].startswith('-'):
+        print ("%s: invalid option %s" % (argv[0], argv[1]), file=sys.stderr)
+        sys.exit(1)
+
+    data = KconfigData(mode)
     parser = KconfigParser(data)
     for arg in argv[3:]:
         m = re.match(r'^(CONFIG_[A-Z0-9_]+)=([yn]?)$', arg)