Add the project loader function in order to implement the editing non destructive...
[bertos.git] / wizard / bertos_utils.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3 #
4 # This file is part of BeRTOS.
5 #
6 # Bertos is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 #
20 # As a special exception, you may use this file as part of a free software
21 # library without restriction.  Specifically, if other files instantiate
22 # templates or use macros or inline functions from this file, or you compile
23 # this file and link it with other files to produce an executable, this
24 # file does not by itself cause the resulting executable to be covered by
25 # the GNU General Public License.  This exception does not however
26 # invalidate any other reasons why the executable file might be covered by
27 # the GNU General Public License.
28 #
29 # Copyright 2008 Develer S.r.l. (http://www.develer.com/)
30 #
31 # $Id$
32 #
33 # Author: Lorenzo Berni <duplo@develer.com>
34 #
35
36 import os
37 import fnmatch
38 import glob
39 import re
40 import shutil
41 # Use custom copytree function
42 import copytree
43 import pickle
44
45 import const
46 import plugins
47 import DefineException
48 import BProject
49
50 def isBertosDir(directory):
51    return os.path.exists(directory + "/VERSION")
52
53 def bertosVersion(directory):
54    return open(directory + "/VERSION").readline().strip()
55
56 def loadBertosProject(project_file):
57     project_data = pickle.loads(open(project_file, "r").read())
58     project_info = BProject.BProject()
59     project_info.setInfo("PROJECT_PATH", os.path.dirname(project_file))
60     project_info.setInfo("SOURCES_PATH", project_data["SOURCES_PATH"])
61     loadSourceTree(project_info)
62     cpu_name = project_data["CPU_NAME"]
63     project_info.setInfo("CPU_NAME", cpu_name)
64     cpu_info = loadCpuInfos(project_info)
65     for cpu in cpu_info:
66         if cpu["CPU_NAME"] == cpu_name:
67             project_info.setInfo("CPU_INFOS", cpu)
68             break
69     loadModuleData(project_info, True)
70     return project_info
71
72 def projectFileGenerator(project_info):
73     directory = project_info.info("PROJECT_PATH")
74     project_data = {}
75     enabled_modules = []
76     for module, information in project_info.info("MODULES").items():
77         if information["enabled"]:
78             enabled_modules.append(module)
79     project_data["ENABLED_MODULES"] = enabled_modules
80     project_data["SOURCES_PATH"] = project_info.info("SOURCES_PATH")
81     project_data["TOOLCHAIN"] = project_info.info("TOOLCHAIN")
82     project_data["CPU_NAME"] = project_info.info("CPU_NAME")
83     project_data["SELECTED_FREQ"] = project_info.info("SELECTED_FREQ")
84     return pickle.dumps(project_data)
85
86 def createBertosProject(project_info):
87     directory = project_info.info("PROJECT_PATH")
88     sources_dir = project_info.info("SOURCES_PATH")
89     if os.path.isdir(directory):
90         shutil.rmtree(directory, True)        
91     os.makedirs(directory)
92     f = open(directory + "/project.bertos", "w")
93     f.write(projectFileGenerator(project_info))
94     f.close()
95     # Destination source dir
96     srcdir = directory + "/bertos"
97     shutil.rmtree(srcdir, True)
98     copytree.copytree(sources_dir + "/bertos", srcdir, ignore_list=const.IGNORE_LIST)
99     # Destination makefile
100     makefile = directory + "/Makefile"
101     if os.path.exists(makefile):
102         os.remove(makefile)
103     makefile = open("mktemplates/Makefile").read()
104     makefile = makefileGenerator(project_info, makefile)
105     open(directory + "/Makefile", "w").write(makefile)
106     # Destination project dir
107     prjdir = directory + "/" + os.path.basename(directory)
108     shutil.rmtree(prjdir, True)
109     os.mkdir(prjdir)
110     # Destination hw files
111     hwdir = prjdir + "/hw"
112     shutil.rmtree(hwdir, True)
113     os.mkdir(hwdir)
114     # Copy all the hw files
115     for module, information in project_info.info("MODULES").items():
116         for hwfile in information["hw"]:
117             string = open(sources_dir + "/" + hwfile, "r").read()
118             open(hwdir + "/" + os.path.basename(hwfile), "w").write(string)
119     # Destination configurations files
120     cfgdir = prjdir + "/cfg"
121     shutil.rmtree(cfgdir, True)
122     os.mkdir(cfgdir)
123     # Set to 1 the autoenabled for enabled modules
124     for module, information in project_info.info("MODULES").items():
125         if information["enabled"] and "configuration" in information and information["configuration"] != "":
126             configurations = project_info.info("CONFIGURATIONS")
127             configuration = configurations[information["configuration"]]
128             for start, parameter in configuration["paramlist"]:
129                 if "type" in configuration[parameter]["informations"] and configuration[parameter]["informations"]["type"] == "autoenabled":
130                     configuration[parameter]["value"] = "1"
131             project_info.setInfo("CONFIGURATIONS", configurations)
132     # Copy all the configuration files
133     for configuration, information in project_info.info("CONFIGURATIONS").items():
134         string = open(sources_dir + "/" + configuration, "r").read()
135         for start, parameter in information["paramlist"]:
136             infos = information[parameter]
137             value = infos["value"]
138             if "unsigned" in infos["informations"] and infos["informations"]["unsigned"]:
139                 value += "U"
140             if "long" in infos["informations"] and infos["informations"]["long"]:
141                 value += "L"
142             string = sub(string, parameter, value)
143         f = open(cfgdir + "/" + os.path.basename(configuration), "w")
144         f.write(string)
145         f.close()
146     # Destinatio mk file
147     makefile = open("mktemplates/template.mk", "r").read()
148     makefile = mkGenerator(project_info, makefile)
149     open(prjdir + "/" + os.path.basename(prjdir) + ".mk", "w").write(makefile)
150     # Destination main.c file
151     main = open("srctemplates/main.c", "r").read()
152     open(prjdir + "/main.c", "w").write(main)
153     # Files for selected plugins
154     relevants_files = {}
155     for plugin in project_info.info("OUTPUT"):
156         module = loadPlugin(plugin)
157         relevants_files[plugin] = module.createProject(project_info)
158     project_info.setInfo("RELEVANT_FILES", relevants_files)
159
160 def loadPlugin(plugin):
161     """
162     Returns the given plugin module.
163     """
164     return getattr(__import__("plugins", {}, {}, [plugin]), plugin)
165     
166 def mkGenerator(project_info, makefile):
167     """
168     Generates the mk file for the current project.
169     """
170     mk_data = {}
171     mk_data["$pname"] = os.path.basename(project_info.info("PROJECT_PATH"))
172     mk_data["$cpuflag"] = project_info.info("CPU_INFOS")["CPU_FLAG_NAME"]
173     mk_data["$cpuname"] = project_info.info("CPU_INFOS")["CORE_CPU"]
174     mk_data["$cpuclockfreq"] = project_info.info("SELECTED_FREQ")
175     mk_data["$cflags"] = " ".join(project_info.info("CPU_INFOS")["C_FLAGS"])
176     mk_data["$ldflags"] = " ".join(project_info.info("CPU_INFOS")["LD_FLAGS"])
177     mk_data["$cppflags"] = " ".join(project_info.info("CPU_INFOS")["CPP_FLAGS"])
178     mk_data["$cppaflags"] = " ".join(project_info.info("CPU_INFOS")["CPPA_FLAGS"])
179     mk_data["$cxxflags"] = " ".join(project_info.info("CPU_INFOS")["CXX_FLAGS"])
180     mk_data["$asflags"] = " ".join(project_info.info("CPU_INFOS")["AS_FLAGS"])
181     mk_data["$arflags"] = " ".join(project_info.info("CPU_INFOS")["AR_FLAGS"])
182     mk_data["$csrc"], mk_data["$pcsrc"], mk_data["$cppasrc"], mk_data["$cxxsrc"], mk_data["$asrc"], mk_data["$constants"] = csrcGenerator(project_info)
183     mk_data["$prefix"] = replaceSeparators(project_info.info("TOOLCHAIN")["path"].split("gcc")[0])
184     mk_data["$suffix"] = replaceSeparators(project_info.info("TOOLCHAIN")["path"].split("gcc")[1])
185     mk_data["$main"] = os.path.basename(project_info.info("PROJECT_PATH")) + "/main.c"
186     for key in mk_data:
187         while makefile.find(key) != -1:
188             makefile = makefile.replace(key, mk_data[key])
189     return makefile
190
191 def makefileGenerator(project_info, makefile):
192     """
193     Generate the Makefile for the current project.
194     """
195     # TODO write a general function that works for both the mk file and the Makefile
196     while makefile.find("project_name") != -1:
197         makefile = makefile.replace("project_name", os.path.basename(project_info.info("PROJECT_PATH")))
198     return makefile
199
200 def csrcGenerator(project_info):
201     modules = project_info.info("MODULES")
202     files = project_info.info("FILES")
203     if "harvard" in project_info.info("CPU_INFOS")["CPU_TAGS"]:
204         harvard = True
205     else:
206         harvard = False
207     # file to be included in CSRC variable
208     csrc = []
209     # file to be included in PCSRC variable
210     pcsrc = []
211     # files to be included in CPPASRC variable
212     cppasrc = []
213     # files to be included in CXXSRC variable
214     cxxsrc = []
215     # files to be included in ASRC variable
216     asrc = []
217     # constants to be included at the beginning of the makefile
218     constants = {}
219     for module, information in modules.items():
220         module_files = set([])
221         dependency_files = set([])
222         # assembly sources
223         asm_files = set([])
224         hwdir = os.path.basename(project_info.info("PROJECT_PATH")) + "/hw" 
225         if information["enabled"]:
226             if "constants" in information:
227                 constants.update(information["constants"])
228             cfiles, sfiles = findModuleFiles(module, project_info)
229             module_files |= set(cfiles)
230             asm_files |= set(sfiles)
231             for file in information["hw"]:
232                 if file.endswith(".c"):
233                     module_files |= set([hwdir + "/" + os.path.basename(file)])
234             for file_dependency in information["depends"]:
235                 if file_dependency in files:
236                     dependencyCFiles, dependencySFiles = findModuleFiles(file_dependency, project_info)
237                     dependency_files |= set(dependencyCFiles)
238                     asm_files |= set(dependencySFiles)
239             for file in module_files:
240                 if not harvard or information.get("harvard", "both") == "both":
241                     csrc.append(file)
242                 if harvard and "harvard" in information:
243                     pcsrc.append(file)
244             for file in dependency_files:
245                 csrc.append(file)
246             for file in project_info.info("CPU_INFOS")["C_SRC"]:
247                 csrc.append(file)
248             for file in project_info.info("CPU_INFOS")["PC_SRC"]:
249                 pcsrc.append(file)
250             for file in asm_files:
251                 cppasrc.append(file)
252     for file in project_info.info("CPU_INFOS")["CPPA_SRC"]:
253         cppasrc.append(file)
254     for file in project_info.info("CPU_INFOS")["CXX_SRC"]:
255         cxxsrc.append(file)
256     for file in project_info.info("CPU_INFOS")["ASRC"]:
257         asrc.append(file)
258     csrc = " \\\n\t".join(csrc) + " \\"
259     pcsrc = " \\\n\t".join(pcsrc) + " \\"
260     cppasrc = " \\\n\t".join(cppasrc) + " \\"
261     cxxsrc = " \\\n\t".join(cxxsrc) + " \\"
262     asrc = " \\\n\t".join(asrc) + " \\"
263     constants = "\n".join([os.path.basename(project_info.info("PROJECT_PATH")) + "_" + key + " = " + unicode(value) for key, value in constants.items()])
264     return csrc, pcsrc, cppasrc, cxxsrc, asrc, constants
265
266 def findModuleFiles(module, project_info):
267     # Find the files related to the selected module
268     cfiles = []
269     sfiles = []
270     # .c files related to the module and the cpu architecture
271     for filename, path in findDefinitions(module + ".c", project_info) + \
272             findDefinitions(module + "_" + project_info.info("CPU_INFOS")["TOOLCHAIN"] + ".c", project_info):
273         path = path.replace(project_info.info("SOURCES_PATH") + os.sep, "")
274         path = replaceSeparators(path)
275         cfiles.append(path + "/" + filename)
276     # .s files related to the module and the cpu architecture
277     for filename, path in findDefinitions(module + ".s", project_info) + \
278             findDefinitions(module + "_" + project_info.info("CPU_INFOS")["TOOLCHAIN"] + ".s", project_info) + \
279             findDefinitions(module + ".S", project_info) + \
280             findDefinitions(module + "_" + project_info.info("CPU_INFOS")["TOOLCHAIN"] + ".S", project_info):
281         path = path.replace(project_info.info("SOURCES_PATH") + os.sep, "")
282         path = replaceSeparators(path)
283         sfiles.append(path + "/" + filename)
284     # .c and .s files related to the module and the cpu tags
285     for tag in project_info.info("CPU_INFOS")["CPU_TAGS"]:
286         for filename, path in findDefinitions(module + "_" + tag + ".c", project_info):
287             path = path.replace(project_info.info("SOURCES_PATH") + os.sep, "")
288             if os.sep != "/":
289                 path = replaceSeparators(path)
290             cfiles.append(path + "/" + filename)
291         for filename, path in findDefinitions(module + "_" + tag + ".s", project_info) + \
292                 findDefinitions(module + "_" + tag + ".S", project_info):
293             path = path.replace(project_info.info("SOURCES_PATH") + os.sep, "")
294             path = replaceSeparators(path)
295             sfiles.append(path + "/" + filename)
296     return cfiles, sfiles
297
298 def replaceSeparators(path):
299     """
300     Replace the separators in the given path with unix standard separator.
301     """
302     if os.sep != "/":
303         while path.find(os.sep) != -1:
304             path = path.replace(os.sep, "/")
305     return path
306
307 def getSystemPath():
308     path = os.environ["PATH"]
309     if os.name == "nt":
310         path = path.split(";")
311     else:
312         path = path.split(":")
313     return path
314
315 def findToolchains(path_list):
316     toolchains = []
317     for element in path_list:
318         for toolchain in glob.glob(element+ "/" + const.GCC_NAME):
319             toolchains.append(toolchain)
320     return list(set(toolchains))
321
322 def getToolchainInfo(output):
323     info = {}
324     expr = re.compile("Target: .*")
325     target = expr.findall(output)
326     if len(target) == 1:
327         info["target"] = target[0].split("Target: ")[1]
328     expr = re.compile("gcc version [0-9,.]*")
329     version = expr.findall(output)
330     if len(version) == 1:
331         info["version"] = version[0].split("gcc version ")[1]
332     expr = re.compile("gcc version [0-9,.]* \(.*\)")
333     build = expr.findall(output)
334     if len(build) == 1:
335         build = build[0].split("gcc version ")[1]
336         build = build[build.find("(") + 1 : build.find(")")]
337         info["build"] = build
338     expr = re.compile("Configured with: .*")
339     configured = expr.findall(output)
340     if len(configured) == 1:
341         info["configured"] = configured[0].split("Configured with: ")[1]
342     expr = re.compile("Thread model: .*")
343     thread = expr.findall(output)
344     if len(thread) == 1:
345         info["thread"] = thread[0].split("Thread model: ")[1]
346     return info
347
348 def loadSourceTree(project):
349     fileList = [f for f in os.walk(project.info("SOURCES_PATH"))]
350     project.setInfo("FILE_LIST", fileList)
351
352 def findDefinitions(ftype, project):
353     L = project.info("FILE_LIST")
354     definitions = []
355     for element in L:
356         for filename in element[2]:
357             if fnmatch.fnmatch(filename, ftype):
358                 definitions.append((filename, element[0]))
359     return definitions
360
361 def loadCpuInfos(project):
362     cpuInfos = []
363     for definition in findDefinitions(const.CPU_DEFINITION, project):
364         cpuInfos.append(getInfos(definition))
365     return cpuInfos
366
367 def getTagSet(cpu_info):
368     tag_set = set([])
369     for cpu in cpu_info:
370         tag_set |= set([cpu["CPU_NAME"]])
371         tag_set |= set(cpu["CPU_TAGS"])
372         tag_set |= set([cpu["CORE_CPU"]])
373         tag_set |= set([cpu["TOOLCHAIN"]])
374     return tag_set
375         
376
377 def getInfos(definition):
378     D = {}
379     D.update(const.CPU_DEF)
380     def include(filename, dict = D, directory=definition[1]):
381         execfile(directory + "/" + filename, {}, D)
382     D["include"] = include
383     include(definition[0], D)
384     D["CPU_NAME"] = definition[0].split(".")[0]
385     D["DEFINITION_PATH"] = definition[1] + "/" + definition[0]
386     del D["include"]
387     return D
388
389 def getCommentList(string):
390     comment_list = re.findall(r"/\*{2}\s*([^*]*\*(?:[^/*][^*]*\*+)*)/", string)
391     comment_list = [re.findall(r"^\s*\* *(.*?)$", comment, re.MULTILINE) for comment in comment_list]
392     return comment_list
393
394 def loadModuleDefinition(first_comment):
395     to_be_parsed = False
396     module_definition = {}
397     for num, line in enumerate(first_comment):
398         index = line.find("$WIZ$")
399         if index != -1:
400             to_be_parsed = True
401             try:
402                 exec line[index + len("$WIZ$ "):] in {}, module_definition
403             except:
404                 raise ParseError(num, line[index:])
405         elif line.find("\\brief") != -1:
406             module_definition["module_description"] = line[line.find("\\brief") + len("\\brief "):]
407     module_dict = {}
408     if "module_name" in module_definition:
409         module_name = module_definition[const.MODULE_DEFINITION["module_name"]]
410         del module_definition[const.MODULE_DEFINITION["module_name"]]
411         module_dict[module_name] = {}
412         if const.MODULE_DEFINITION["module_depends"] in module_definition:
413             depends = module_definition[const.MODULE_DEFINITION["module_depends"]]
414             del module_definition[const.MODULE_DEFINITION["module_depends"]]
415             if type(depends) == str:
416                 depends = (depends,)
417             module_dict[module_name]["depends"] = depends
418         else:
419             module_dict[module_name]["depends"] = ()
420         if const.MODULE_DEFINITION["module_configuration"] in module_definition:
421             module_dict[module_name]["configuration"] = module_definition[const.MODULE_DEFINITION["module_configuration"]]
422             del module_definition[const.MODULE_DEFINITION["module_configuration"]]
423         else:
424             module_dict[module_name]["configuration"] = ""
425         if "module_description" in module_definition:
426             module_dict[module_name]["description"] = module_definition["module_description"]
427             del module_definition["module_description"]
428         if const.MODULE_DEFINITION["module_harvard"] in module_definition:
429             harvard = module_definition[const.MODULE_DEFINITION["module_harvard"]]
430             module_dict[module_name]["harvard"] = harvard
431             del module_definition[const.MODULE_DEFINITION["module_harvard"]]
432         if const.MODULE_DEFINITION["module_hw"] in module_definition:
433             hw = module_definition[const.MODULE_DEFINITION["module_hw"]]
434             del module_definition[const.MODULE_DEFINITION["module_hw"]]
435             if type(hw) == str:
436                 hw = (hw, )
437             module_dict[module_name]["hw"] = hw
438         else:
439             module_dict[module_name]["hw"] = ()
440         if const.MODULE_DEFINITION["module_supports"] in module_definition:
441             supports = module_definition[const.MODULE_DEFINITION["module_supports"]]
442             del module_definition[const.MODULE_DEFINITION["module_supports"]]
443             module_dict[module_name]["supports"] = supports
444         module_dict[module_name]["constants"] = module_definition
445         module_dict[module_name]["enabled"] = False
446     return to_be_parsed, module_dict
447
448 def isSupported(project, module=None, property_id=None):
449     if not module and property_id:
450         item = project.info("CONFIGURATIONS")[property_id[0]][property_id[1]]["informations"]
451     else:
452         item = project.info("MODULES")[module]
453     tag_dict = project.info("ALL_CPU_TAGS")
454     if "supports" in item:
455         support_string = item["supports"]
456         supported = {}
457         try:
458             exec "supported = " + support_string in tag_dict, supported
459         except:
460             raise SupportedException(support_string)
461         return supported["supported"]
462     else:
463         return True
464
465 def loadDefineLists(comment_list):
466     define_list = {}
467     for comment in comment_list:
468         for num, line in enumerate(comment):
469             index = line.find("$WIZ$")
470             if index != -1:
471                 try:
472                     exec line[index + len("$WIZ$ "):] in {}, define_list
473                 except:
474                     raise ParseError(num, line[index:])
475     for key, value in define_list.items():
476         if type(value) == str:
477             define_list[key] = (value,)
478     return define_list
479
480 def getDescriptionInformations(comment):
481     """
482     Take the doxygen comment and strip the wizard informations, returning the tuple
483     (comment, wizard_information)
484     """
485     brief = ""
486     description = ""
487     information = {}
488     for num, line in enumerate(comment):
489         index = line.find("$WIZ$")
490         if index != -1:
491             if len(brief) == 0:
492                 brief += line[:index].strip()
493             else:
494                 description += " " + line[:index]
495             try:
496                 exec line[index + len("$WIZ$ "):] in {}, information
497             except:
498                 raise ParseError(num, line[index:])
499         else:
500             if len(brief) == 0:
501                 brief += line.strip()
502             else:
503                 description += " " + line
504                 description = description.strip()
505     return brief.strip(), description.strip(), information
506
507 def getDefinitionBlocks(text):
508     """
509     Take a text and return a list of tuple (description, name-value).
510     """
511     block = []
512     block_tmp = re.finditer(r"/\*{2}\s*([^*]*\*(?:[^/*][^*]*\*+)*)/\s*#define\s+((?:[^/]*?/?)+)\s*?(?:/{2,3}[^<].*?)?$", text, re.MULTILINE)
513     for match in block_tmp:
514         # Only the first element is needed
515         comment = match.group(1)
516         define = match.group(2)
517         start = match.start()
518         block.append(([re.findall(r"^\s*\* *(.*?)$", line, re.MULTILINE)[0] for line in comment.splitlines()], define, start))
519     for match in re.finditer(r"/{3}\s*([^<].*?)\s*#define\s+((?:[^/]*?/?)+)\s*?(?:/{2,3}[^<].*?)?$", text, re.MULTILINE):
520         comment = match.group(1)
521         define = match.group(2)
522         start = match.start()
523         block.append(([comment], define, start))
524     for match in re.finditer(r"#define\s*(.*?)\s*/{3}<\s*(.+?)\s*?(?:/{2,3}[^<].*?)?$", text, re.MULTILINE):
525         comment = match.group(2)
526         define = match.group(1)
527         start = match.start()
528         block.append(([comment], define, start))
529     return block
530
531 def loadModuleData(project, edit=False):
532     module_info_dict = {}
533     list_info_dict = {}
534     configuration_info_dict = {}
535     file_dict = {}
536     for filename, path in findDefinitions("*.h", project) + findDefinitions("*.c", project) + findDefinitions("*.s", project) + findDefinitions("*.S", project):
537         comment_list = getCommentList(open(path + "/" + filename, "r").read())
538         if len(comment_list) > 0:
539             module_info = {}
540             configuration_info = {}
541             try:
542                 to_be_parsed, module_dict = loadModuleDefinition(comment_list[0])
543             except ParseError, err:
544                 raise DefineException.ModuleDefineException(path, err.line_number, err.line)
545             for module, information in module_dict.items():
546                 if "depends" not in information:
547                     information["depends"] = ()
548                 information["depends"] += (filename.split(".")[0],)
549                 information["category"] = os.path.basename(path)
550                 if "configuration" in information and len(information["configuration"]):
551                     configuration = module_dict[module]["configuration"]
552                     try:
553                         configuration_info[configuration] = loadConfigurationInfos(project.info("SOURCES_PATH") + "/" + configuration)
554                     except ParseError, err:
555                         raise DefineException.ConfigurationDefineException(project.info("SOURCES_PATH") + "/" + configuration, err.line_number, err.line)
556                     if edit:
557                         try:
558                             path = os.path.basename(project.info("PROJECT_PATH"))
559                             directory = project.info("PROJECT_PATH")
560                             user_configuration = loadConfigurationInfos(directory + "/" + configuration.replace("bertos", path))
561                             configuration_info[configuration] = updateConfigurationValues(configuration_info[configuration], user_configuration)
562                         except ParseError, err:
563                             raise DefineException.ConfigurationDefineException(directory + "/" + configuration.replace("bertos", path))
564             module_info_dict.update(module_dict)
565             configuration_info_dict.update(configuration_info)
566             if to_be_parsed:
567                 try:
568                     list_dict = loadDefineLists(comment_list[1:])
569                     list_info_dict.update(list_dict)
570                 except ParseError, err:
571                     raise DefineException.EnumDefineException(path, err.line_number, err.line)
572     for filename, path in findDefinitions("*_" + project.info("CPU_INFOS")["TOOLCHAIN"] + ".h", project):
573         comment_list = getCommentList(open(path + "/" + filename, "r").read())
574         list_info_dict.update(loadDefineLists(comment_list))
575     for tag in project.info("CPU_INFOS")["CPU_TAGS"]:
576         for filename, path in findDefinitions("*_" + tag + ".h", project):
577             comment_list = getCommentList(open(path + "/" + filename, "r").read())
578             list_info_dict.update(loadDefineLists(comment_list))
579     project.setInfo("MODULES", module_info_dict)
580     project.setInfo("LISTS", list_info_dict)
581     project.setInfo("CONFIGURATIONS", configuration_info_dict)
582     project.setInfo("FILES", file_dict)
583
584 def formatParamNameValue(text):
585     """
586     Take the given string and return a tuple with the name of the parameter in the first position
587     and the value in the second.
588     """
589     block = re.findall("\s*([^\s]+)\s*(.+?)\s*$", text, re.MULTILINE)
590     return block[0]
591
592 def loadConfigurationInfos(path):
593     """
594     Return the module configurations found in the given file as a dict with the
595     parameter name as key and a dict containig the fields above as value:
596         "value": the value of the parameter
597         "description": the description of the parameter
598         "informations": a dict containig optional informations:
599             "type": "int" | "boolean" | "enum"
600             "min": the minimum value for integer parameters
601             "max": the maximum value for integer parameters
602             "long": boolean indicating if the num is a long
603             "unsigned": boolean indicating if the num is an unsigned
604             "value_list": the name of the enum for enum parameters
605     """
606     configuration_infos = {}
607     configuration_infos["paramlist"] = []
608     for comment, define, start in getDefinitionBlocks(open(path, "r").read()):
609         name, value = formatParamNameValue(define)
610         brief, description, informations = getDescriptionInformations(comment)
611         configuration_infos["paramlist"].append((start, name))
612         configuration_infos[name] = {}
613         configuration_infos[name]["value"] = value
614         configuration_infos[name]["informations"] = informations
615         if not "type" in configuration_infos[name]["informations"]:
616             configuration_infos[name]["informations"]["type"] = findParameterType(configuration_infos[name])
617         if ("type" in configuration_infos[name]["informations"] and
618                 configuration_infos[name]["informations"]["type"] == "int" and
619                 configuration_infos[name]["value"].find("L") != -1):
620             configuration_infos[name]["informations"]["long"] = True
621             configuration_infos[name]["value"] = configuration_infos[name]["value"].replace("L", "")
622         if ("type" in configuration_infos[name]["informations"] and
623                 configuration_infos[name]["informations"]["type"] == "int" and
624                 configuration_infos[name]["value"].find("U") != -1):
625             configuration_infos[name]["informations"]["unsigned"] = True
626             configuration_infos[name]["value"] = configuration_infos[name]["value"].replace("U", "")
627         configuration_infos[name]["description"] = description
628         configuration_infos[name]["brief"] = brief
629     return configuration_infos
630
631 def updateConfigurationValues(def_conf, user_conf):
632     for param in def_conf["paramlist"]:
633         def_conf[param[1]]["value"] = user_conf[param[1]]["value"]
634     return def_conf
635
636 def findParameterType(parameter):
637     if "value_list" in parameter["informations"]:
638         return "enum"
639     if "min" in parameter["informations"] or "max" in parameter["informations"] or re.match(r"^\d+U?L?$", parameter["value"]) != None:
640         return "int"
641
642 def sub(string, parameter, value):
643     """
644     Substitute the given value at the given parameter define in the given string
645     """
646     return re.sub(r"(?P<define>#define\s+" + parameter + r"\s+)([^\s]+)", r"\g<define>" + value, string)
647
648 def isInt(informations):
649     """
650     Return True if the value is a simple int.
651     """
652     if ("long" not in informatios or not informations["long"]) and ("unsigned" not in informations or informations["unsigned"]):
653         return True
654     else:
655         return False
656
657 def isLong(informations):
658     """
659     Return True if the value is a long.
660     """
661     if "long" in informations and informations["long"] and "unsigned" not in informations:
662         return True
663     else:
664         return False
665
666 def isUnsigned(informations):
667     """
668     Return True if the value is an unsigned.
669     """
670     if "unsigned" in informations and informations["unsigned"] and "long" not in informations:
671         return True
672     else:
673         return False
674
675 def isUnsignedLong(informations):
676     """
677     Return True if the value is an unsigned long.
678     """
679     if "unsigned" in informations and "long" in informations and informations["unsigned"] and informations["long"]:
680         return True
681     else:
682         return False
683
684 class ParseError(Exception):
685     def __init__(self, line_number, line):
686         Exception.__init__(self)
687         self.line_number = line_number
688         self.line = line
689
690 class SupportedException(Exception):
691     def __init__(self, support_string):
692         Exception.__init__(self)
693         self.support_string = support_string