__author__ = "Steffen Vogel" __copyright__ = "Copyright 2015-2017, Steffen Vogel" __license__ = "GPLv3" __maintainer__ = "Steffen Vogel" __email__ = "post@steffenvogel.de" """ This file is part of transWhat transWhat 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 3 of the License, or any later version. transwhat 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 transWhat. If not, see . """ # I'm guessing this is the format of the spectrum config file in BNF # ::= * # ::= * * | # ::=
| #
::= [*] # ::= * = * class SpectrumConfig: """ Represents spectrum2 configuration options. """ def __init__(self, path_to_config_file): """ Initialises configuration file. Args: path_to_config_file: The absolute path to the configuration file. """ self.config_path = path_to_config_file self.options = self.loadConfig(self.config_path) # Load backend_logging information self.options.update(self.loadConfig(self['logging.backend_config'])) def loadConfig(self, file_name): section = {'a': ""} # Current section heading, # It's a dictionary because variables in python closures can't be # assigned to. options = dict() # Recursive descent parser def consume_spaces(line): i = 0 for c in line: if c != ' ': break i += 1 return line[i:] def read_identifier(line): i = 0 for c in line: if c == ' ' or c==']' or c=='[' or c=='=': break i += 1 # no identifier if i == 0: return (None, 'No identifier') return (line[:i], line[i:]) def parse_section(line): if len(line) == 0 or line[0] != '[': return (None, 'expected [') line = line[1:] identifier, line = read_identifier(line) if len(line) == 0 or line[0] != ']' or identifier is None: return (None, line) return (identifier, line[1:]) def parse_assignment(line): key, line = read_identifier(line) if key is None: return (None, None, line) line = consume_spaces(line) if len(line) == 0 or line[0] != '=': return (None, None, 'Expected =') line = consume_spaces(line[1:]) value = line[:-1] return (key, value, '\n') def expr(line): sec, newline = parse_section(line) if sec is not None: section['a'] = sec else: key, value, newline = parse_assignment(line) if key is not None: if section['a'] != '': options[section['a'] + '.' + key] = value else: options[key] = value else: return (None, newline) return (newline, None) def parse_line(line, line_number): line = consume_spaces(line) if line == '\n': return newline, error = expr(line) if newline is None: raise ConfigParseError(str(line_number) + ': ' + error + ': ' + repr(line)) newline = consume_spaces(newline) if newline != '\n': raise ConfigParseError(str(line_number) + ': Expected newline got ' + repr(newline)) def strip_comments(line): i = 0 for c in line: if c == '#' or c == '\n': break i += 1 return line[:i] + '\n' with open(file_name, 'r') as f: i = 1 while True: line = f.readline() if line == '': break parse_line(strip_comments(line), i) i += 1 return options def __getitem__(self, key): return self.options[key] class ConfigParseError(Exception): pass