From 14b150bcf5e17f2b3e0be871eff387f60ed8bf71 Mon Sep 17 00:00:00 2001
From: Erik Kooistra <kooistra@astron.nl>
Date: Tue, 19 Apr 2016 05:59:39 +0000
Subject: [PATCH] Added fileSections argument to specifiy target specific
 section headers in the config dictionary file.

---
 tools/oneclick/base/common_dict_file.py | 71 ++++++++++++++++---------
 tools/oneclick/base/modelsim_config.py  | 12 +++--
 tools/oneclick/base/quartus_config.py   | 11 +++-
 3 files changed, 64 insertions(+), 30 deletions(-)

diff --git a/tools/oneclick/base/common_dict_file.py b/tools/oneclick/base/common_dict_file.py
index 05c4c10a43..35efeb9c23 100644
--- a/tools/oneclick/base/common_dict_file.py
+++ b/tools/oneclick/base/common_dict_file.py
@@ -25,17 +25,29 @@
    pairs. These key - value pairs are read from the file and kept in a
    single dictionary of keys and values.
 
-   The format of the dictionary file is similar to that of an ini file but
-   without the sections. For ini files Python has the ConfigParser package.
-   Effectively the dictionary file only contains one section. It is not
-   obvious how to deal with sections if only one dictionary needs to be
-   stored flat. Defining a single section, is misleading because it suggests
-   that more sections are supported. Alternatively prepending a dummy
-   section when the file is read is also a bit awkward. In fact the parsing
-   by read_dict_file() is relatively simple and the other methods would also
-   be needed if the ConfigParser would be used. Therefore the Python
-   ConfigParser package for ini files is not used.
-
+   The format of the dictionary file is similar to that of an ini file. For ini
+   files Python has the ConfigParser package, but that is not used here because
+   the ini file specification is not very strict. The parsing can be done in
+   a single method read_dict_file() that gives more freedom for interprating
+   the ini file.
+   
+   Like an ini file the dictionary can contain one or more sections. The first
+   section is common, has no header and always included. The specific sections
+   have a header that is marked by [section header]. The square brackets '['
+   and ']' are used to identify the section header. If the 'section header' is
+   included in the object argument fileSections list then the keys of that
+   section will be included in the dictionary.
+   
+     'fileSections' = None  --> ignore fileSections to include all sections in
+                                the dict.
+     'fileSections' = []    --> empty list to include only the common first
+                                section in the dict.
+     'fileSections' = ['section header' ...] -->
+                                dedicated list of one or more section header
+                                strings to include these specific sections,
+                                and also the common first section, in the
+                                dict.
+                                
    The key and value string in the dictionary file are separated by '='. Hence
    the '=' character can not be used in keys. The '=' can be used in values,
    because subsequent '=' on the same line are part of the value.
@@ -93,7 +105,7 @@ import collections
 
 class CommonDictFile:
 
-    def __init__(self, rootDir, fileName='dict.txt'):
+    def __init__(self, rootDir, fileName='dict.txt', fileSections=None):
         """Store the dictionaries from all fileName files in rootDir."""
         self.CDF_COMMENT = '#'
         self.CDF_SEPARATOR = '='
@@ -105,6 +117,7 @@ class CommonDictFile:
         self.filePathNames = []                             # list of all directory paths + fileName of the available dictionary files
         for path in self.filePaths:
             self.filePathNames.append(os.path.join(path, self.fileName))
+        self.fileSections = fileSections                    # specific dictionary file sections to include in the dict
         self.dicts = self.read_all_dict_files()             # list of dictionaries that are read from the available dictionary files
         self.nof_dicts = len(self.dicts)                    # number of dictionaries = number of dictorary files
 
@@ -146,26 +159,36 @@ class CommonDictFile:
             read_dicts.append(self.read_dict_file(fp))
         return read_dicts
 
-    def read_dict_file(self, filePathName=None, valueSeparator=' '):
+    def read_dict_file(self, filePathName=None):
         """Read the dictionary information the filePathName file."""
         if filePathName==None: filePathName=self.filePathNames[0]
         file_dict = collections.OrderedDict()
+        section_headers = []
         with open(filePathName, 'r') as fp:
-            lineNr=0
+            include_section = True      # default include all sections
             key = ''
             value = ''
             for line in fp:
-                if line.find(self.CDF_COMMENT)==-1:          # strip lines with comment
-                    key_end = line.find(self.CDF_SEPARATOR)  # find key
-                    if key_end>=0:
-                        key = line[0:key_end].strip()        # new key
-                        value = line[key_end+1:].strip()     # new value
+                if line.find(self.CDF_COMMENT)==-1:          # Strip lines with comment
+                    section_begin= line.find('[')            # Search for [section] header in this line
+                    section_end  = line.find(']')
+                    if section_begin>=0 and section_end>section_begin:
+                        section_header = line[section_begin+1:section_end].strip()  # new section header
+                        section_headers.append(section_header)
+                        if self.fileSections!=None:
+                            if section_header not in self.fileSections:
+                                include_section = False          # skip this section
                     else:
-                        value += valueSeparator              # replace newline by valueSeparator
-                        value += line.strip()                # append value
-                    if key!='':
-                        file_dict[key] = value.strip()       # update key in dict
-                lineNr += 1
+                        key_end = line.find(self.CDF_SEPARATOR)  # Search for key in this line
+                        if key_end>=0:
+                            key = line[0:key_end].strip()        # new key
+                            value = line[key_end+1:].strip()     # new value
+                        else:
+                            value += ' '                         # replace newline by space to separate values
+                            value += line.strip()                # append value
+                        if include_section==True and key!='':
+                            file_dict[key] = value.strip()       # Update dict with key and values
+            file_dict['section_headers'] = section_headers       # Add the section headers as a key-value pair to the dict
         return file_dict
 
     def write_dict_file(self, dicts, filePathNames, keySeparator=None):
diff --git a/tools/oneclick/base/modelsim_config.py b/tools/oneclick/base/modelsim_config.py
index c703121544..0aa945dee8 100755
--- a/tools/oneclick/base/modelsim_config.py
+++ b/tools/oneclick/base/modelsim_config.py
@@ -21,6 +21,9 @@
 ###############################################################################
 
 """HDL configuration for building Modelsim simulation targets.
+
+   Usage:
+   > python $RADIOHDL/tools/oneclick/base/modelsim_config.py -t unb1
 """
 
 import common as cm
@@ -35,6 +38,8 @@ class ModelsimConfig(hdl_config.HdlConfig):
     def __init__(self, toolRootDir, libFileName='hdllib.cfg', toolFileName='hdltool_<toolset>.cfg'):
         """Get Modelsim tool info from toolRootDir and all HDL library info from libRootDir.
         
+           This class uses the default keys and the keys from the libFileSections in the libFileName config file.
+           
            Arguments:
            - toolRootDir     : Root directory from where the hdltool_<toolset>.cfg file is searched for.
            - libFileName     : Default HDL library configuration file name
@@ -72,7 +77,8 @@ class ModelsimConfig(hdl_config.HdlConfig):
              The <lib_name>_lib_order.txt files are read by the TCL commands.do file in Modelsim. Creating the files in Python
              and then reading them in TCL makes the commands.do much simpler.
         """
-        hdl_config.HdlConfig.__init__(self, toolRootDir, libFileName, toolFileName)
+        libFileSections=['modelsim_project_file']
+        hdl_config.HdlConfig.__init__(self, toolRootDir, libFileName, libFileSections, toolFileName)
 
     def read_compile_order_from_mpf(self, mpfPathName):
         """Utility to read the compile order of the project files from an existing <mpfPathName>.mpf."""
@@ -144,7 +150,7 @@ class ModelsimConfig(hdl_config.HdlConfig):
                 # Write [Library] section for all used libraries
                 fp.write('[Library]\n')
                 # . map used vendor technology libs to their target directory
-                for technologyName in cm.listify(self.technologyNames):
+                for technologyName in self.technologyNames:
                     tech_dict = self.read_hdl_libraries_technology_file(technologyName)
                     for lib_clause, lib_work in tech_dict.iteritems():
                         fp.write('%s = %s\n' % (lib_clause, lib_work))
@@ -326,7 +332,6 @@ if __name__ == '__main__':
         msim = ModelsimConfig(toolRootDir=os.path.expandvars('$RADIOHDL/tools'), libFileName='hdllib.cfg', toolFileName=toolFileName)
         
         if arg_verbosity>=2:
-            print arg_verbosity
             print '#'
             print '# ModelsimConfig:'
             print '#'
@@ -340,7 +345,6 @@ if __name__ == '__main__':
             print 'Derive library compile order = ', msim.derive_lib_order('sim')
 
         if arg_verbosity>=2:
-            print arg_verbosity
             print ''
             print 'get_lib_build_dirs for simulation:'
             for sim_dir in msim.get_lib_build_dirs('sim'):
diff --git a/tools/oneclick/base/quartus_config.py b/tools/oneclick/base/quartus_config.py
index 1a976800a7..9a46ad5332 100755
--- a/tools/oneclick/base/quartus_config.py
+++ b/tools/oneclick/base/quartus_config.py
@@ -21,6 +21,9 @@
 ###############################################################################
 
 """HDL configuration for building Quartus synthesis targets.
+
+   Usage:
+   > python $RADIOHDL/tools/oneclick/base/quartus_config.py -t unb1
 """
 
 import common as cm
@@ -35,6 +38,8 @@ class QuartusConfig(hdl_config.HdlConfig):
     def __init__(self, toolRootDir, libFileName='hdllib.cfg', toolFileName='hdltool_<toolset>.cfg'):
         """Get Quartus tool info from toolRootDir and all HDL library info from libRootDir.
         
+           This class uses the default keys and the keys from the libFileSections in the libFileName config file.
+           
            Arguments:
            - toolRootDir     : Root directory from where the hdltool_<toolset>.cfg file is searched for.
            - libFileName     : Default HDL library configuration file name
@@ -57,7 +62,9 @@ class QuartusConfig(hdl_config.HdlConfig):
            - <lib_name>.qsf : Quartus settings file (QSF) for a certain HDL library based on the hdllib.cfg. The file is created by
                               create_quartus_settings_file(). There is one QSF per Quartus synthesis project.
         """
-        hdl_config.HdlConfig.__init__(self, toolRootDir, libFileName, toolFileName)
+        libFileSections=['quartus_project_file']
+        libFileSections=None
+        hdl_config.HdlConfig.__init__(self, toolRootDir, libFileName, libFileSections, toolFileName)
 
     def create_quartus_ip_lib_file(self, lib_names=None):
         """Create the Quartus IP file <hdl_lib_name>_lib.qip for all HDL libraries. The <hdl_lib_name>.qip file contains the list of files that are given
@@ -226,7 +233,7 @@ if __name__ == '__main__':
     # Parse command line arguments
     toolsetSelect = ['unb1', 'unb2', 'unb2a']
 
-    argparser = argparse.ArgumentParser(description='Create Modelsim mpf files for all hdllib.cfg')
+    argparser = argparse.ArgumentParser(description='Create Quartus project files for hdllib.cfg')
     argparser.add_argument('-t','--toolset', help='choose toolset %s (default: %s)' % (toolsetSelect,toolsetSelect[0]), default=toolsetSelect[0], required=False)
     argparser.add_argument('-v','--verbosity', help='verbosity >= 0 for more info', type=int, default=0, required=False)
     args = vars(argparser.parse_args())
-- 
GitLab