packages: Remove obsolete Maemo packaging files
[strongswan.git] / conf / format-options.py
index e591f37..3073943 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright (C) 2014 Tobias Brunner
+# Copyright (C) 2014-2015 Tobias Brunner
 # Hochschule fuer Technik Rapperswil
 #
 # This program is free software; you can redistribute it and/or modify it
@@ -48,6 +48,14 @@ full.section.name {[#]}
 
 If a # is added between the curly braces the section header will be commented
 out in the configuration file snippet, which is useful for example sections.
+
+Dots in section/option names may be escaped with a backslash.  For instance,
+with the following section description
+
+charon.filelog./var/log/daemon\.log {}
+       Section to define logging into /var/log/daemon.log
+
+/var/log/daemon.log will be the name of the last section.
 """
 
 import sys
@@ -58,17 +66,18 @@ from operator import attrgetter
 
 class ConfigOption:
        """Representing a configuration option or described section in strongswan.conf"""
-       def __init__(self, name, default = None, section = False, commented = False):
-               self.name = name.split('.')[-1]
-               self.fullname = name
+       def __init__(self, path, default = None, section = False, commented = False):
+               self.path = path
+               self.name = path[-1]
+               self.fullname = '.'.join(path)
                self.default = default
                self.section = section
                self.commented = commented
                self.desc = []
                self.options = []
 
-       def __cmp__(self, other):
-               return  cmp(self.name, other.name)
+       def __lt__(self, other):
+               return self.name < other.name
 
        def add_paragraph(self):
                """Adds a new paragraph to the description"""
@@ -92,8 +101,9 @@ class ConfigOption:
 
 class Parser:
        """Parses one or more files of configuration options"""
-       def __init__(self):
+       def __init__(self, sort = True):
                self.options = []
+               self.sort = sort
 
        def parse(self, file):
                """Parses the given file and adds all options to the internal store"""
@@ -112,7 +122,8 @@ class Parser:
                if m:
                        if self.__current:
                                self.__add_option(self.__current)
-                       self.__current = ConfigOption(m.group('name'), m.group('default'),
+                       path = self.__split_name(m.group('name'))
+                       self.__current = ConfigOption(path, m.group('default'),
                                                                                  commented = not m.group('assign'))
                        return
                # section definition
@@ -120,7 +131,8 @@ class Parser:
                if m:
                        if self.__current:
                                self.__add_option(self.__current)
-                       self.__current = ConfigOption(m.group('name'), section = True,
+                       path = self.__split_name(m.group('name'))
+                       self.__current = ConfigOption(path, section = True,
                                                                                  commented = m.group('comment'))
                        return
                # paragraph separator
@@ -132,11 +144,14 @@ class Parser:
                if m and self.__current:
                        self.__current.add(m.group('text'))
 
+       def __split_name(self, name):
+               """Split the given full name in a list of section/option names"""
+               return [x.replace('\.', '.') for x in re.split(r'(?<!\\)\.', name)]
+
        def __add_option(self, option):
                """Adds the given option to the abstract storage"""
                option.desc = [desc for desc in option.desc if len(desc)]
-               parts = option.fullname.split('.')
-               parent = self.__get_option(parts[:-1], True)
+               parent = self.__get_option(option.path[:-1], True)
                if not parent:
                        parent = self
                found = next((x for x in parent.options if x.name == option.name
@@ -145,28 +160,28 @@ class Parser:
                        found.adopt(option)
                else:
                        parent.options.append(option)
-                       parent.options.sort()
+                       if self.sort:
+                               parent.options.sort()
 
-       def __get_option(self, parts, create = False):
+       def __get_option(self, path, create = False):
                """Searches/Creates the option (section) based on a list of section names"""
                option = None
                options = self.options
-               fullname = ""
-               for name in parts:
-                       fullname += '.' + name if len(fullname) else name
+               for i, name in enumerate(path, 1):
                        option = next((x for x in options if x.name == name and x.section), None)
                        if not option:
                                if not create:
                                        break
-                               option = ConfigOption(fullname, section = True)
+                               option = ConfigOption(path[:i], section = True)
                                options.append(option)
-                               options.sort()
+                               if self.sort:
+                                       options.sort()
                        options = option.options
                return option
 
        def get_option(self, name):
                """Retrieves the option with the given name"""
-               return self.__get_option(name.split('.'))
+               return self.__get_option(self.__split_name(name))
 
 class TagReplacer:
        """Replaces formatting tags in text"""
@@ -227,32 +242,32 @@ class ConfFormatter:
                if len(opt.desc):
                        self.__wrapper.initial_indent = '{0}# '.format(self.__indent * indent)
                        self.__wrapper.subsequent_indent = self.__wrapper.initial_indent
-                       print format(self.__wrapper.fill(self.__tags.replace(opt.desc[0])))
+                       print(self.__wrapper.fill(self.__tags.replace(opt.desc[0])))
 
        def __print_option(self, opt, indent, commented):
                """Print a single option with description and default value"""
                comment = "# " if commented or opt.commented else ""
                self.__print_description(opt, indent)
                if opt.default:
-                       print '{0}{1}{2} = {3}'.format(self.__indent * indent, comment, opt.name, opt.default)
+                       print('{0}{1}{2} = {3}'.format(self.__indent * indent, comment, opt.name, opt.default))
                else:
-                       print '{0}{1}{2} ='.format(self.__indent * indent, comment, opt.name)
-               print
+                       print('{0}{1}{2} ='.format(self.__indent * indent, comment, opt.name))
+               print('')
 
        def __print_section(self, section, indent, commented):
                """Print a section with all options"""
                commented = commented or section.commented
                comment = "# " if commented else ""
                self.__print_description(section, indent)
-               print '{0}{1}{2} {{'.format(self.__indent * indent, comment, section.name)
-               print
+               print('{0}{1}{2} {{'.format(self.__indent * indent, comment, section.name))
+               print('')
                for o in sorted(section.options, key=attrgetter('section')):
                        if o.section:
                                self.__print_section(o, indent + 1, commented)
                        else:
                                self.__print_option(o, indent + 1, commented)
-               print '{0}{1}}}'.format(self.__indent * indent, comment)
-               print
+               print('{0}{1}}}'.format(self.__indent * indent, comment))
+               print('')
 
        def format(self, options):
                """Print a list of options"""
@@ -283,14 +298,14 @@ class ManFormatter:
                if option.section and not len(option.desc):
                        return
                if option.section:
-                       print '.TP\n.B {0}\n.br'.format(option.fullname)
+                       print('.TP\n.B {0}\n.br'.format(option.fullname))
                else:
-                       print '.TP'
+                       print('.TP')
                        default = option.default if option.default else ''
-                       print '.BR {0} " [{1}]"'.format(option.fullname, default)
+                       print('.BR {0} " [{1}]"'.format(option.fullname, default))
                for para in option.desc if len(option.desc) < 2 else option.desc[1:]:
-                       print self.__groffize(self.__wrapper.fill(para))
-                       print ''
+                       print(self.__groffize(self.__wrapper.fill(para)))
+                       print('')
 
        def format(self, options):
                """Print a list of options"""
@@ -310,9 +325,12 @@ options.add_option("-f", "--format", dest="format", type="choice", choices=["con
 options.add_option("-r", "--root", dest="root", metavar="NAME",
                                   help="root section of which options are printed, "
                                   "if not found everything is printed")
+options.add_option("-n", "--nosort", action="store_false", dest="sort",
+                                  default=True, help="do not sort sections alphabetically")
+
 (opts, args) = options.parse_args()
 
-parser = Parser()
+parser = Parser(opts.sort)
 if len(args):
        for filename in args:
                try: