# Copyright (C) 2004 Nicolas Delon # All Rights Reserved # # This file is part of the Prelude program. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. import re class Error(Exception): pass class ParseError(Error): def __init__(self, filename, lineno, line): self.filename = filename self.lineno = lineno self.line = line def __str__(self): return "parse error in \"%s\" at %s line %d" % (self.line.rstrip(), self.filename, self.lineno) class OrderedDict(dict): def __init__(self): dict.__init__(self) self._ordered_key_list = [ ] def __delitem__(self, key): dict.__delitem__(self, key) self._ordered_key_list.remove(key) def __setitem__(self, key, value): dict.__setitem__(self, key, value) if not key in self._ordered_key_list: self._ordered_key_list.append(key) def values(self): return map(lambda k: self[k], self._ordered_key_list) def keys(self): return self._ordered_key_list def copy(self): new = OrderedDict() for key in self.keys(): new[key] = self[key] return new class ConfigParserSection(OrderedDict): def __init__(self, name): OrderedDict.__init__(self) self.name = name def getOption(self, name): return self[name] def getOptions(self): return self.values() class ConfigParserOption: def __init__(self, name, value, lineno, line): self.name = name self.value = value self.lineno = lineno self.line = line def getName(self): return self.name def getValue(self): return self.value def getLineno(self): return self.lineno def getLine(self): return self.line class ConfigParser: """ A config parser class ala ConfigParser.ConfigParser (only read operations are (will be) supported). ConfigParser.ConfigParser did not feed all our needs: - we need the '= value' part of option to be optionnal - we need to support special characters (like ':') in option name (for urls) - we need to keep the right order of options in sections (this is done via the OrderedDict class that subclass dict) """ EMPTY_LINE_REGEXP = re.compile("^\s*(\#.*)?$") SECTION_REGEXP = re.compile("\[\s*(?P\w+)\s*\]") OPTION_REGEXP = re.compile("^\s*(?P\S+)\s*(?:\=?\s*(?P\S+))?$") def __init__(self, filename): self.filename = filename self._sections = OrderedDict() self._root_section = OrderedDict() self._current_section = self._root_section def load(self): lineno = 0 for line in open(self.filename).readlines(): lineno += 1 result = self.EMPTY_LINE_REGEXP.match(line) if result: continue else: result = self.SECTION_REGEXP.match(line) if result: name = result.group("name") self._current_section = self._sections[name] = ConfigParserSection(name) else: result = self.OPTION_REGEXP.match(line) if result: name, value = result.group("name", "value") self._current_section[name] = ConfigParserOption(name, value, lineno, line) else: raise ParseError(file.name, lineno, line) def getSection(self, name): return self._sections[name] def getSections(self): return self._sections.values() if __name__ == "__main__": conf = ConfigParser() conf.readfp(open("prelude-fic.conf")) for section in conf.sections(): print "[%s]" % section for option in conf.options(section): print option, conf.get(section, option)