OpenCores
URL https://opencores.org/ocsvn/radiohdl/radiohdl/trunk

Subversion Repositories radiohdl

[/] [radiohdl/] [trunk/] [core/] [hdl_raw_access.py] - Rev 4

Compare with Previous | Blame | View Log

###############################################################################
#
# Copyright (C) 2014-2018
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
#
# 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 3 of the License, 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.  If not, see <http://www.gnu.org/licenses/>.
#
# $Id$
#
###############################################################################
 
import re
import os.path
from configfile import *
from configtree import ConfigTree
 
__all__ = ['RawConfigFile', 'RawConfigTree']
 
"""
File that implements the configfile <-> configtree concept but this time with the
intention to modify the keys and/or values in those configfiles. So the content of
the configfiels is kept as raw as possible.
"""
 
 
class RawConfigFile(object):
    """
    Class that holds the raw content of a configfile. To simplify the manipulation of the
    content the file is internally stored as lines.
    """
    def __init__(self, filename):
        """
        Read the hdl configuration file and check presence of the required keys.
        :raise ConfigFileException
        """
        full_filename = os.path.expanduser(os.path.expandvars(filename))
        if not os.path.isfile(full_filename):
            raise ConfigFileException("configfile '%s' not found" % full_filename)
 
        self.filename = full_filename
        self.content  = open(self.filename, 'r').readlines()
 
    @property
    def ID(self):
        "Returns uniq ID (string) to identify this particular file. Fullfilename is used."
        return self.filename
 
    def _save_content(self, verbose=False):
        """
        Write the content to the file.
        """
        with open(self.filename, 'w') as fp:
            fp.writelines(self.content)
 
        if verbose:
            print(self.filename)
 
    def change_value(self, key, new_value, verbose):
        """
        Change the value of the given key. The old value may be empty, be on one or multiple lines.
        The new value may use \n characters to create a new multiline value.
        """
        # Search the key in the lines
        prog = re.compile("^{}[ \t]*{}".format(key, CFG_ASSIGNMENT_CHAR))
        for (linenr, line) in enumerate(self.content):
            # search if line starts with this key
            match = prog.search(line)
            if not match:
                continue
 
            # replace the value that is on this line with the whole new value
            value_start = match.end()
            line = line[0:value_start] + ' ' + new_value.replace("\\n", "\n") + "\n"
            self.content[linenr] = line
 
            # to support removing old multiline values we have to skip lines until we find a
            # sectionheader|other key|empty line or are at the end of the file
            linenr += 1
            while linenr < len(self.content):
                if not re.match(r"(\[[a-zA-Z0-9_]+\]|[a-zA-Z0-9_]+[ \t]*{}|^[ \t]*$)".format(CFG_ASSIGNMENT_CHAR), self.content[linenr]):
                    self.content.pop(linenr)
                else:
                    break
 
            self._save_content(verbose)
            break
 
    def append_key_value(self, key, value, verbose):
        """
        Append the given key and value to the end of the configfile.
        \n characters can be used both in the key and the value to start at a new line.
        """
        self.content.append("{} {} {}\n".format(key.replace("\\n", "\n"),
                                                CFG_ASSIGNMENT_CHAR,
                                                value.replace("\\n", "\n")))
        self._save_content(verbose)
 
    def rename_key(self, old_key, new_key, verbose):
        """
        Change the name of a key.
        """
        # Search the key in the lines
        prog = re.compile("^{}[ \t]*{}".format(old_key, CFG_ASSIGNMENT_CHAR))
        for (linenr, line) in enumerate(self.content):
            # search if line starts with this old_key
            match = prog.search(line)
            if not match:
                continue
 
            # change the name of the key
            value_start = match.end()
            line = "{} {}{}\n".format(new_key.replace("\\n", "\n"), CFG_ASSIGNMENT_CHAR, line[value_start:])
            self.content[linenr] = line
            self._save_content(verbose)
            break
 
    def remove_key(self, key, verbose):
        """
        Remove a key and value pair from the dictfile.
        """
        # difficulty here is that we can delete the lines immediately because the enumeration over the
        # file content gets messed up. So we setup the variables first_line and last_line that mark
        # the part of the list that has to be removed. After the enumeration we cut the lines.
 
        # First search the key in the lines
        searching_key     = True
        last_line         = len(self.content)
        key_mask          = re.compile(r"^{}[ \t]*{}".format(key, CFG_ASSIGNMENT_CHAR))
        end_of_value_mask = re.compile(r"(\[[a-zA-Z0-9_]+\]|[a-zA-Z0-9_]+[ \t]*{})".format(CFG_ASSIGNMENT_CHAR))
        for (linenr, line) in enumerate(self.content):
            if searching_key:
                # search if line starts with this key
                match = key_mask.search(line)
                if match:
                    first_line = linenr
                    searching_key = False
            else:
                # not searching for the key anymore, we now have to find the and of the value.
                # to support removing old multiline values we have to skip lines until we find a
                # sectionheader|other key or are at the end of the file
                if not end_of_value_mask.match(self.content[linenr]):
                    continue
                last_line = linenr
                break
 
        del self.content[first_line:last_line]
        self._save_content(verbose)
 
    def insert_key_at_linenr(self, new_key, new_value, linenumber, verbose):
        """
        Insert a new key = value pair in the configfile at linenumber. The first line has number 1.
        """
        if linenumber > len(self.content):
            return self.append_key_value(new_key, new_value, verbose)
 
        # Read dict file into string and insert new key = value pair at insertLineNr
        new_line = "{} {} {}\n".format(new_key.replace("\\n", "\n"), CFG_ASSIGNMENT_CHAR, new_value)
        self.content.insert(linenumber-1, new_line)
        self._save_content(verbose)
 
    def insert_key_value_before_key(self, new_key, new_value, before_key, verbose):
        """
        Insert a new key = value pair in the configfile just before another key..
        """
        # Search the key in the lines
        prog = re.compile("^{}[ \t]*{}".format(before_key, CFG_ASSIGNMENT_CHAR))
        for (linenr, line) in enumerate(self.content):
            # search if line starts with this key
            match = prog.search(line)
            if not match:
                continue
 
            return self.insert_key_at_linenr(new_key, new_value, linenr+1, verbose)
 
 
class RawConfigTree(ConfigTree):
    """
    Class the represents the collection of 'raw content' configfiles.
    """
    def __init__(self, rootdirs, filename, sections=None):
        """
        Read the raw configuration files and stores them in this tree.
        :raise ConfigFileException
        """
        super(RawConfigTree, self).__init__(rootdirs, filename, sections)
 
    def _factory_constructor(self, full_filename):
        "Function for returning the readin configfile."
        return RawConfigFile(full_filename)
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.