Index: kefile.config
===================================================================
--- Makefile.config	(revision 79305e1c8bf5ba84f34db2d351014ae9f611c7e8)
+++ 	(revision )
@@ -1,52 +1,0 @@
-## General configuration directives
-#
-# CONFIG_SMP (n/y)
-#       Support for symetric multiprocessors
-#
-# CONFIG_HT (n/y)
-#       Improved support for hyperthreading
-#
-# CONFIG_FPU_LAZY (n/y)
-#       Lazy context switching
-#
-
-CONFIG_SMP = y
-CONFIG_HT = y
-CONFIG_FPU_LAZY = y
-
-## Debugging configuration directives
-#
-# CONFIG_DEBUG (n/y)
-#       General debuging and assert checking
-#
-# CONFIG_DEBUG_SPINLOCK (n/y)
-#       Deadlock detection support for spinlocks
-#
-
-CONFIG_DEBUG = y
-CONFIG_DEBUG_SPINLOCK = y
-
-## Run-time configuration directives
-#
-# CONFIG_USERSPACE (n/y)
-#       Enable user space support
-#
-# CONFIG_TEST (value)
-#       Compile in test "value" (empty string for no test)
-#
-
-CONFIG_USERSPACE = n
-CONFIG_TEST =
-#CONFIG_TEST = synch/rwlock1
-#CONFIG_TEST = synch/rwlock2
-#CONFIG_TEST = synch/rwlock3
-#CONFIG_TEST = synch/rwlock4
-#CONFIG_TEST = synch/rwlock5
-#CONFIG_TEST = synch/semaphore1
-#CONFIG_TEST = synch/semaphore2
-#CONFIG_TEST = fpu/fpu1
-#CONFIG_TEST = fpu/sse1
-#CONFIG_TEST = fpu/mips1
-#CONFIG_TEST = print/print1
-#CONFIG_TEST = thread/thread1
-#CONFIG_TEST = mm/mapping1
Index: configure
===================================================================
--- configure	(revision 34722eec48a3738a79af032a3ee21e3eead183db)
+++ configure	(revision 34722eec48a3738a79af032a3ee21e3eead183db)
@@ -0,0 +1,1 @@
+tools/config.py
Index: kernel.config
===================================================================
--- kernel.config	(revision 34722eec48a3738a79af032a3ee21e3eead183db)
+++ kernel.config	(revision 34722eec48a3738a79af032a3ee21e3eead183db)
@@ -0,0 +1,40 @@
+## General configuration directives
+
+# Support for symetric multiprocessors
+! CONFIG_SMP (y/n)
+
+# Improved support for hyperthreading
+! CONFIG_HT (y/n)
+
+# Lazy context switching
+! CONFIG_FPU_LAZY (y/n)
+
+## Debugging configuration directives
+
+# General debuging and assert checking
+! CONFIG_DEBUG (y/n)
+
+# Deadlock detection support for spinlocks
+! CONFIG_DEBUG_SPINLOCK (y/n)
+
+## Run-time configuration directives
+
+# Enable user space support
+! CONFIG_USERSPACE (n/y)
+
+# Kernel test type
+@ "" No test
+@ "synch/rwlock1" Read write test 1
+@ "synch/rwlock2" Read write test 2
+@ "synch/rwlock3" Read write test 3
+@ "synch/rwlock4" Read write test 4
+@ "synch/rwlock5" Read write test 5
+@ "synch/semaphore1" Semaphore test 1
+@ "synch/semaphore2" Sempahore test 2
+@ "fpu/fpu1" Intel fpu test 1
+@ "fpu/sse1" Intel Sse test 1
+@ "fpu/mips1" Mips FPU test 1
+@ "print/print1" Printf test 1
+@ "thread/trhead1" Thread test 1
+@ "mm/mapping" Mapping test 1
+! CONFIG_TEST (choice)
Index: tools/build
===================================================================
--- tools/build	(revision 79305e1c8bf5ba84f34db2d351014ae9f611c7e8)
+++ tools/build	(revision 34722eec48a3738a79af032a3ee21e3eead183db)
@@ -61,3 +61,4 @@
 fi
 
+tools/config.py default
 make all "ARCH=$ARCH" "TAG=$TAG" $ARGS
Index: tools/config.py
===================================================================
--- tools/config.py	(revision 34722eec48a3738a79af032a3ee21e3eead183db)
+++ tools/config.py	(revision 34722eec48a3738a79af032a3ee21e3eead183db)
@@ -0,0 +1,268 @@
+#!/usr/bin/env python
+"""
+Kernel configuration script
+"""
+import sys
+import os
+import re
+
+INPUT = 'kernel.config'
+OUTPUT = 'Makefile.config'
+TMPOUTPUT = 'Makefile.config.tmp'
+
+class DefaultDialog:
+    "Wrapper dialog that tries to return default values"
+    def __init__(self, dlg):
+        self.dlg = dlg
+
+    def set_title(self,text):
+        self.dlg.set_title(text)
+        
+    def yesno(self, text, default=None):
+        if default is not None:
+            return default
+        return self.dlg.yesno(text, default)
+    def noyes(self, text, default=None):
+        if default is not None:
+            return default
+        return self.dlg.noyes(text, default)
+    
+    def choice(self, text, choices, defopt=None):
+        if defopt is not None:
+            return choices[defopt][0]
+        return self.dlg.choice(text, choices, defopt)
+
+class NoDialog:
+    def __init__(self):
+        self.printed = None
+        self.title = 'HelenOS Configuration'
+
+    def print_title(self):
+        if not self.printed:
+            sys.stdout.write("*** %s ***\n" % self.title)
+            self.printed = True
+
+    def set_title(self, text):
+        self.title = text
+        self.printed = False
+    
+    def noyes(self, text, default=None):
+        if not default:
+            default = 'n'
+        return self.yesno(text, default)
+    
+    def yesno(self, text, default=None):
+        self.print_title()
+        
+        if default != 'n':
+            default = 'y'
+        while 1:
+            sys.stdout.write("%s (y/n)[%s]: " % (text,default))
+            inp = sys.stdin.readline()
+            if not inp:
+                raise EOFError
+            inp = inp.strip().lower()
+            if not inp:
+                return default
+            if inp == 'y':
+                return 'y'
+            elif inp == 'n':
+                return 'n'
+
+    def _print_choice(self, text, choices, defopt):
+        sys.stdout.write('%s:\n' % text)
+        for i,(text,descr) in enumerate(choices):
+            sys.stdout.write('\t%2d. %s\n' % (i, descr))
+        if defopt is not None:
+            sys.stdout.write('Enter choice number[%d]: ' % defopt)
+        else:
+            sys.stdout.write('Enter choice number: ')
+        
+    def choice(self, text, choices, defopt=None):
+        self.print_title()
+        while 1:
+            self._print_choice(text, choices, defopt)
+            inp = sys.stdin.readline()
+            if not inp:
+                raise EOFError
+            if not inp.strip():
+                if defopt is not None:
+                    return choices[defopt][0]
+                continue
+            try:
+                number = int(inp.strip())
+            except ValueError:
+                continue
+            if number < 0 or number >= len(choices):
+                continue
+            return choices[number][0]
+
+
+class Dialog(NoDialog):
+    def __init__(self):
+        NoDialog.__init__(self)
+        self.dlgcmd = os.environ.get('DIALOG','dialog')
+        self.title = 'HelenOS Configuration'
+        
+        if os.system('%s --print-maxsize >/dev/null 2>&1' % self.dlgcmd) != 0:
+            raise NotImplementedError
+
+    def set_title(self,text):
+        self.title = text
+        
+    def calldlg(self,*args,**kw):
+        indesc, outdesc = os.pipe()
+        pid = os.fork()
+        if not pid:
+            os.close(2)
+            os.dup(outdesc)
+            os.close(indesc)
+            
+            dlgargs = [self.dlgcmd,'--title',self.title]
+            for key,val in kw.items():
+                dlgargs.append('--'+key)
+                dlgargs.append(val)
+            dlgargs += args            
+            os.execlp(self.dlgcmd,*dlgargs)
+
+        os.close(outdesc)
+        errout = os.fdopen(indesc,'r')
+        data = errout.read()
+        errout.close()
+            
+        pid,status = os.wait()
+        if not os.WIFEXITED(status):
+            raise EOFError
+        status = os.WEXITSTATUS(status)
+        if status == 255:
+            raise EOFError
+        return status,data
+        
+    def yesno(self, text, default=None):
+        text = text + ':'
+        width = '50'
+        height = '5'
+        if len(text) < 48:
+            text = ' '*int(((48-len(text))/2)) + text
+        else:
+            width = '0'
+            height = '0'
+        if default == 'n':
+            res,data = self.calldlg('--defaultno','--yesno',text,height,width)
+        else:
+            res,data = self.calldlg('--yesno',text,height,width)
+
+        if res == 0:
+            return 'y'
+        return 'n'
+    
+    def choice(self, text, choices, defopt=None):
+        text = text + ':'
+        width = '50'
+        height = str(8 + len(choices))
+        args = []
+        for key,val in choices:
+            args.append(key)
+            args.append(val)
+
+        kw = {}
+        if defopt:
+            kw['default-item'] = choices[defopt][0] 
+        res,data = self.calldlg('--nocancel','--menu',text,height,width,
+                                str(len(choices)),*args, **kw)
+        if res:
+            print data
+            raise EOFError
+        return data
+    
+def read_defaults(fname):
+    defaults = {}
+    f = file(fname,'r')
+    for line in f:
+        res = re.match(r'^([^#]\w*)\s*=\s*(.*?)\s*$', line)
+        if res:
+            defaults[res.group(1)] = res.group(2)
+    f.close()
+    return defaults
+
+def parse_config(input, output, dlg, defaults={}):
+    f = file(input, 'r')
+    outf = file(output, 'w')
+
+    outf.write('#########################################\n')
+    outf.write('## AUTO-GENERATED FILE, DO NOT EDIT!!! ##\n')
+    outf.write('#########################################\n\n')
+
+    comment = ''
+    default = None
+    choices = []
+    for line in f:        
+        if line.startswith('!'):
+            res = re.search(r'!\s*([^\s]+)\s*\((.*)\)\s*$', line)
+            if not res:
+                raise RuntimeError("Weird line: %s" % line)
+            varname = res.group(1)
+            vartype = res.group(2)
+
+            default = defaults.get(varname,None)
+
+            if vartype == 'y/n':
+                result = dlg.yesno(comment, default)
+            elif vartype == 'n/y':
+                result = dlg.noyes(comment, default)
+            elif vartype == 'choice':
+                defopt = None
+                if default is not None:
+                    for i,(key,val) in enumerate(choices):
+                        if key == default:
+                            defopt = i
+                            break
+                result = dlg.choice(comment, choices, defopt)
+            else:
+                raise RuntimeError("Bad method: %s" % vartype)
+            outf.write('%s = %s\n' % (varname, result))
+            # Clear cumulated values
+            comment = ''
+            default = None
+            choices = []
+            continue
+        
+        if line.startswith('@'):
+            res = re.match(r'@\s*"(.*?)"\s*(.*)$', line)
+            if not res:
+                raise RuntimeError("Bad line: %s" % line)
+            choices.append((res.group(1), res.group(2)))
+            continue
+        
+        outf.write(line)
+        if re.match(r'^#[^#]', line):
+            comment = line[1:].strip()
+        elif line.startswith('##'):
+            dlg.set_title(line[2:].strip())
+        
+    outf.close()
+    f.close()
+
+def main():
+    defaults = {}
+    try:
+        dlg = Dialog()
+    except NotImplementedError:
+        dlg = NoDialog()
+
+    # Default run will update the configuration file
+    # with newest options
+    if len(sys.argv) == 2 and sys.argv[1]=='default':
+        dlg = DefaultDialog(dlg)
+
+    if os.path.exists(OUTPUT):
+        defaults = read_defaults(OUTPUT)
+    
+    parse_config(INPUT, TMPOUTPUT, dlg, defaults)
+    if os.path.exists(OUTPUT):
+        os.unlink(OUTPUT)
+    os.rename(TMPOUTPUT, OUTPUT)
+        
+
+if __name__ == '__main__':
+    main()
