142 lines
3.8 KiB
Python
142 lines
3.8 KiB
Python
__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 <http://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
# I'm guessing this is the format of the spectrum config file in BNF
|
|
# <config_file> ::= <line>*
|
|
# <line> ::= <space>* <expr> <space>* <newline> | <space*>
|
|
# <expr> ::= <section> | <assignment>
|
|
# <section> ::= [<identifier>*]
|
|
# <assignment> ::= <identifier> <space>* = <space>* <value>
|
|
|
|
|
|
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
|