//parsing KConfig static PropertyList ParserKConfig(string pKFile) { string typ = ""; string name = "", UID = "", min = "", max = ""; bool newProperty = false, flHelp = false, flEnum = false; var def = ""; string lstHelp = ""; List <PropertyEntry> ListProperties = new List <PropertyEntry>(); PropertyEntry PropEntry = new PropertyEntry.Boolean(); bool BoolNameChoice = false; PropertyEntry.Enumerated.Suggestion SugEnum = null;// new PropertyEntry.Enumerated.Suggestion(); List <PropertyEntry.Enumerated.Suggestion> lstSugEnum = new List <PropertyEntry.Enumerated.Suggestion>(); int aCounrEnumDef = 0; int resParse; string lnHist = ""; foreach (var ln in File.ReadAllLines(pKFile)) { if (ln.Contains("menu \"Example Configuration\"")) { resParse = 3; } Match m = Regex.Match(ln, "^(menuconfig|config|choice)[ ]+([A-Z0-9_]+)"); if (m.Success) { if (flEnum) { SugEnum = new PropertyEntry.Enumerated.Suggestion(); SugEnum.InternalValue = m.Groups[2].Value; if (m.Groups[2].Value == def) { def = $"{aCounrEnumDef}"; } aCounrEnumDef++; } if (m.Groups[1].Value == "choice") { BoolNameChoice = true; flEnum = true; } if (m.Groups[1].Value == "config") { BoolNameChoice = false; } if (name != "")//save { if (typ == "string") { PropEntry = new PropertyEntry.String { Name = name, UniqueID = UID, Description = lstHelp, DefaultValue = def }; } if (typ == "int") { PropEntry = new PropertyEntry.Integral { Name = name, UniqueID = UID, Description = lstHelp, DefaultValue = Int32.TryParse(def, out resParse) ? Int32.Parse(def) : 0, MinValue = Int32.TryParse(min, out resParse) ? Int32.Parse(min) : 0, MaxValue = Int32.TryParse(max, out resParse) ? Int32.Parse(max) : 0x0FFFFFFF }; // break; } if (typ == "bool") { PropEntry = new PropertyEntry.Boolean { Name = name, UniqueID = UID, Description = lstHelp, DefaultValue = def.ToLower().Contains("y") ? true : false }; // break; } ListProperties.Add(PropEntry); if (!flEnum) { lstHelp = "";//.Clear(); } flHelp = false; } UID = m.Groups[2].Value; newProperty = true; } if (!newProperty) { continue; } if (flHelp && !ln.TrimStart().StartsWith("#") && ln.Length > 1) { lstHelp += ln.Trim(); } m = Regex.Match(ln, "^[ \t]+(int|bool|hex|prompt)[ ]+[\"]?([\\w0-9_ ]*)[\"]?"); if (m.Success) { if (flEnum) { if (m.Groups[1].Value == "bool" && !BoolNameChoice) { SugEnum.UserFriendlyName = m.Groups[2].Value; lstSugEnum.Add(SugEnum); continue; } // if (m.Groups[1].Value == "prompt") // throw new Exception(" no endchoice "+ lnHist); } typ = m.Groups[1].Value; name = m.Groups[2].Value; // if (typ == "prompt") flEnum = true; continue; } m = Regex.Match(ln, "^[ \t]+default[ \t]([\\w\\d]+)"); if (m.Success) { def = m.Groups[1].Value; continue; } m = Regex.Match(ln, "^[ \t]+range[ \t]([\\w\\d]+)[ \t]+([\\w\\d]+)"); if (m.Success) { min = m.Groups[1].Value; max = m.Groups[2].Value; continue; } if (Regex.IsMatch(ln, "^[ \t]+help[ \t]*")) { flHelp = true; continue; } if (Regex.IsMatch(ln, "^[ \t]*endchoice[ \t]*")) // end prompt { if (typ != "prompt" && typ != "bool") { throw new Exception(" no prompt in endchoice"); } flEnum = false; PropEntry = new PropertyEntry.Enumerated { Name = name, // UniqueID = UID, Description = lstHelp, DefaultEntryIndex = 1,// def.ToLower().StartsWith("y") ? true : false SuggestionList = lstSugEnum.ToArray() }; // break; ListProperties.Add(PropEntry); lstHelp = "";//.Clear(); flHelp = false; aCounrEnumDef = 0; } lnHist = ln; } // end file //save old record , need it to new function or class if (typ == "int") { PropEntry = new PropertyEntry.Integral { Name = name, UniqueID = UID, Description = lstHelp, DefaultValue = Int32.TryParse(def, out resParse) ? Int32.Parse(def) : 0, MinValue = Int32.TryParse(min, out resParse) ? Int32.Parse(min) : 0, MaxValue = Int32.TryParse(max, out resParse) ? Int32.Parse(max) : 0x0FFFFFFF }; // break; } if (typ == "bool") { PropEntry = new PropertyEntry.Boolean { Name = name, UniqueID = UID, Description = lstHelp, DefaultValue = def.ToLower().Contains("y") ? true : false }; // break; } ListProperties.Add(PropEntry); //----------------------- List <PropertyGroup> lstPrGr = new List <PropertyGroup>(); PropertyGroup PrGr = new PropertyGroup(); PrGr.Properties = ListProperties; lstPrGr.Add(PrGr); PropertyList ConfigurableProperties = new PropertyList { PropertyGroups = lstPrGr }; return(ConfigurableProperties); }
public ToolFlags CopyAndBuildFlags(BSPBuilder bsp, List <string> projectFiles, string subdir, ref PropertyList configurableProperties) { List <ParsedCondition> conditions = null; List <string> allConditions = new List <string>(); if (SimpleFileConditions != null) { allConditions.AddRange(SimpleFileConditions); } if (SmartFileConditions != null) { foreach (var str in SmartFileConditions) { int idx = str.IndexOf('|'); string name = str.Substring(0, idx); string id = "com.sysprogs.bspoptions." + name.Replace(' ', '_'); string[] values = str.Substring(idx + 1).Split(';'); PropertyEntry entry; if (values.Length == 1) { var val = values[0]; string regex, value; idx = val.IndexOf("=>"); if (idx == -1) { regex = val; value = "1"; } else { regex = val.Substring(0, idx); value = val.Substring(idx + 2); } allConditions.Add($"{regex}: $${id}$$ == {value}"); entry = new PropertyEntry.Boolean { ValueForTrue = value, Name = name, UniqueID = id, DefaultValue = true }; } else { List <PropertyEntry.Enumerated.Suggestion> suggestions = new List <PropertyEntry.Enumerated.Suggestion>(); foreach (var val in values) { idx = val.IndexOf("=>"); string regex = val.Substring(0, idx); string value = val.Substring(idx + 2); allConditions.Add($"{regex}: $${id}$$ == {value}"); suggestions.Add(new PropertyEntry.Enumerated.Suggestion { InternalValue = value }); } entry = new PropertyEntry.Enumerated { Name = name, UniqueID = id, SuggestionList = suggestions.ToArray() }; } if (configurableProperties?.PropertyGroups == null) { configurableProperties = new PropertyList { PropertyGroups = new List <PropertyGroup>() } } ; var grp = configurableProperties.PropertyGroups.FirstOrDefault(g => g.Name == null && g.UniqueID == null); if (grp == null) { configurableProperties.PropertyGroups.Insert(0, grp = new PropertyGroup()); } grp.Properties.Add(entry); } } if (allConditions.Count > 0) { conditions = new List <ParsedCondition>(); foreach (var cond in allConditions) { int idx = cond.IndexOf(':'); if (idx == -1) { throw new Exception("Invalid simple condition format"); } Regex rgFile = new Regex(cond.Substring(0, idx), RegexOptions.IgnoreCase); string rawCond = cond.Substring(idx + 1).Trim(); Condition parsedCond = ParseCondition(rawCond); conditions.Add(new ParsedCondition { Regex = rgFile, Condition = parsedCond }); } } string expandedSourceFolder = SourceFolder; bsp.ExpandVariables(ref expandedSourceFolder); if (TargetFolder == null) { TargetFolder = Path.GetFileName(expandedSourceFolder); } TargetFolder = TargetFolder.Replace('\\', '/'); if (subdir == null) { subdir = ""; } string absTarget = Path.Combine(bsp.BSPRoot, subdir, TargetFolder); Directory.CreateDirectory(absTarget); string folderInsideBSPPrefix = TargetFolder; if (!string.IsNullOrEmpty(subdir)) { folderInsideBSPPrefix = subdir + "/" + TargetFolder; } folderInsideBSPPrefix = folderInsideBSPPrefix.Replace('\\', '/'); if (folderInsideBSPPrefix == "/") { folderInsideBSPPrefix = ""; } else if (folderInsideBSPPrefix != "" && !folderInsideBSPPrefix.StartsWith("/")) { folderInsideBSPPrefix = "/" + folderInsideBSPPrefix; } var copyMasks = new CopyFilters(FilesToCopy); var autoIncludes = new CopyFilters(AutoIncludeMask); var potentialSymlinks = new CopyFilters(SymlinkResolutionMask); var projectContents = new CopyFilters(ProjectInclusionMask); var filesToCopy = Directory.GetFiles(expandedSourceFolder, "*", SearchOption.AllDirectories).Select(f => f.Substring(expandedSourceFolder.Length + 1)).Where(f => copyMasks.IsMatch(f)).ToArray(); foreach (var dir in filesToCopy.Select(f => Path.Combine(absTarget, Path.GetDirectoryName(f))).Distinct()) { Directory.CreateDirectory(dir); } List <IRenameRule> rules = new List <IRenameRule>(); foreach (var r in (RenameRules ?? "").Split(';').Where(s => s != "")) { int idx = r.IndexOf("=>"); rules.Add(new RenameRule { OldName = r.Substring(0, idx), NewName = r.Substring(idx + 2) }); } foreach (var r in (AdvancedRenameRules ?? "").Split(';').Where(s => s != "")) { int idx = r.IndexOf("=>"); rules.Add(new AdvancedRenamingRule { OldName = new Regex(r.Substring(0, idx), RegexOptions.IgnoreCase), NewNameFormat = r.Substring(idx + 2) }); } var includeDirs = filesToCopy.Where(f => autoIncludes.IsMatch(f)).Select(f => Path.GetDirectoryName(f).Replace('\\', '/')).Distinct().Select(d => "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + (string.IsNullOrEmpty(d) ? "" : ("/" + d))).ToList(); foreach (var f in filesToCopy) { string renamedRelativePath = f; string pathInsidePackage = Path.Combine(subdir, TargetFolder, f); if (pathInsidePackage.Length > 120) { if (!bsp.OnFilePathTooLong(pathInsidePackage)) { continue; } } string targetFile = Path.Combine(absTarget, f); string newName = rules?.FirstOrDefault(r => r.Matches(f))?.Apply(targetFile); if (newName == null) { if (bsp.RenamedFileTable.TryGetValue(targetFile, out newName) || bsp.RenamedFileTable.TryGetValue(targetFile.Replace('/', '\\'), out newName)) { } } if (newName != null) { var oldTargetFile = targetFile; targetFile = Path.Combine(Path.GetDirectoryName(targetFile), newName); renamedRelativePath = Path.Combine(Path.GetDirectoryName(renamedRelativePath), newName); bsp.RenamedFileTable[oldTargetFile] = newName; } if (AlreadyCopied) { if (!File.Exists(targetFile)) { throw new Exception(targetFile + " required by a copy job marked as 'Already Copied' does not exist"); } } else { bool resolved = false; var absSourcePath = Path.Combine(expandedSourceFolder, f); if (potentialSymlinks.IsMatch(f)) { for (; ;) { var contents = File.ReadAllLines(absSourcePath); if (contents.Length == 1 && File.Exists(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0]))) { absSourcePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0])); } else { break; } } } if (!resolved) { File.Copy(absSourcePath, targetFile, true); } } File.SetAttributes(targetFile, File.GetAttributes(targetFile) & ~FileAttributes.ReadOnly); string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + renamedRelativePath.Replace('\\', '/'); if (projectContents.IsMatch(f)) { projectFiles.Add(encodedPath.Replace('\\', '/')); } if (conditions != null) { foreach (var cond in conditions) { if (cond.Regex.IsMatch(f)) { bsp.MatchedFileConditions.Add(new FileCondition { ConditionToInclude = cond.Condition, FilePath = encodedPath }); cond.UseCount++; break; } } } } if (AdditionalProjectFiles != null) { foreach (var spec in AdditionalProjectFiles.Split(';')) { string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + spec; projectFiles.Add(encodedPath); } } var unusedConditions = conditions?.Where(c => c.UseCount == 0)?.ToArray(); if ((unusedConditions?.Length ?? 0) != 0) { throw new Exception(string.Format("Found {0} unused conditions. Please recheck your rules.", unusedConditions.Length)); } if (Patches != null) { foreach (var p in Patches) { foreach (var fn in p.FilePath.Split(';')) { List <string> allLines = File.ReadAllLines(Path.Combine(absTarget, fn)).ToList(); p.Apply(allLines); string targetPath = p.TargetPath; if (targetPath == null) { targetPath = fn; } Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(absTarget, targetPath))); File.WriteAllLines(Path.Combine(absTarget, targetPath), allLines); } } } if (GuardedFiles != null) { foreach (var gf in GuardedFiles) { int idx = gf.IndexOf("=>"); Regex rgFile = new Regex(gf.Substring(0, idx)); string macro = gf.Substring(idx + 2); var fn = Path.Combine(absTarget, filesToCopy.First(f => rgFile.IsMatch(f))); List <string> lines = new List <string>(File.ReadAllLines(fn)); int i = 0; //1. Find first #include for (i = 0; i < lines.Count; i++) { if (lines[i].Trim().StartsWith("#include")) { break; } } //2. Find first non-preprocessor line for (; i < lines.Count; i++) { if (!string.IsNullOrWhiteSpace(lines[i]) && !lines[i].Trim().StartsWith("#include")) { break; } } if (i == lines.Count) { throw new Exception("Cannot find a place to insert guard in " + fn); } lines.Insert(i, string.Format("#if defined({0}) && {0}", macro)); lines.Add("#endif //" + macro); File.WriteAllLines(fn, lines); } } if (AdditionalIncludeDirs != null) { includeDirs.AddRange(AdditionalIncludeDirs.Split(';').Select(d => MapIncludeDir(absTarget, d))); } return(new ToolFlags { PreprocessorMacros = (PreprocessorMacros == null) ? null : PreprocessorMacros.Split(';'), IncludeDirectories = includeDirs.ToArray() }); }
private PropertyEntry ParseSingleProperty(string name, string value, List <string> precedingComments) { var desc = precedingComments.Select(c => rgMacroDescription.Match(c)).FirstOrDefault(m => m.Success && m.Groups[1].Value != "i"); string type = "o", text = name; if (desc != null && desc.Groups[2].Value == name) { type = desc.Groups[1].Value; text = desc.Groups[3].Value.Trim().TrimEnd('.') + $" ({name})"; } PropertyEntry entry; switch (type) { case "q": case "e": entry = new PropertyEntry.Boolean { ValueForTrue = "1", ValueForFalse = "0" }; break; case "o": { var enumValues = precedingComments .Select(c => rgEnumValue.Match(c)) .Where(m => m.Success) .Select(m => new PropertyEntry.Enumerated.Suggestion { InternalValue = m.Groups[1].Value, UserFriendlyName = m.Groups[2].Value }) .ToArray(); if (enumValues.Length > 0) { entry = new PropertyEntry.Enumerated { SuggestionList = enumValues } } ; else { entry = new PropertyEntry.String { } }; break; } case "s": entry = new PropertyEntry.String { }; break; default: return(null); } entry.Name = text; entry.UniqueID = name; entry.Description = precedingComments.Select(c => rgMacroDescription.Match(c)).FirstOrDefault(m => m.Success && m.Groups[1].Value == "i")?.Groups[2].Value.Trim(); return(entry); }
public ConfigurationFileTemplateEx BuildConfigurationFileTemplate(string file, ConfigFileDefinition cf) { Regex rgIfndef = new Regex("^#ifndef ([^ ]+)"); DefineClass valuelessDefine = new DefineClass(@"#define ([^ ]+)( *)$", "#define {name}{g2: }", @"^/\* *#define ([^ ]+)( *)\*/$", "/* #define {name} */"); DefineClass defineWithValue = MakeRegularDefineClass(); Regex rgGroup = new Regex(@" */\* #+ ([^#]*) #+ \*/"); Regex rgHalModuleMacro = new Regex("HAL_(.*)MODULE_ENABLED"); PropertyList propertyList = new PropertyList { PropertyGroups = new List <PropertyGroup>() }; PropertyGroup group = null; string lastIfndef = null; List <TestableConfigurationFileParameter> testableParameters = new List <TestableConfigurationFileParameter>(); foreach (var line in File.ReadAllLines(file)) { string previousLineIfndef = lastIfndef; lastIfndef = null; Match m; bool isInverse; if (line.Trim() == "") { continue; } if ((m = rgGroup.Match(line)).Success) { if (group != null && group.Properties.Count > 0) { propertyList.PropertyGroups.Add(group); } group = new PropertyGroup { Name = m.Groups[1].Value.Trim() }; } else if ((m = rgIfndef.Match(line)).Success) { lastIfndef = m.Groups[1].Value; } else { PropertyEntry prop = null; if (valuelessDefine.IsMatch(line, out m, out isInverse)) { var macro = m.Groups[valuelessDefine.MacroNameGroup].Value; if (macro.EndsWith("HAL_CONF_H")) { continue; } valuelessDefine.FoundDefines.Add(macro); string userFriendlyName = macro; if ((m = rgHalModuleMacro.Match(macro)).Success) { string moduleName = m.Groups[1].Value; if (moduleName == "") { userFriendlyName = "Enable the HAL framework"; } else { userFriendlyName = $"Enable the {moduleName.TrimEnd('_')} module"; } } prop = new PropertyEntry.Boolean { Name = userFriendlyName, ValueForTrue = "1", ValueForFalse = "", UniqueID = macro, DefaultValue = !isInverse }; if (macro != "HAL_MODULE_ENABLED") { testableParameters.Add(new TestableConfigurationFileParameter { Name = macro, DisabledValue = "", EnabledValue = "1" }); } } else if (defineWithValue.IsMatch(line, out m, out isInverse)) { var macro = m.Groups[defineWithValue.MacroNameGroup].Value; var value = m.Groups[defineWithValue.ValueGroup].Value; var text = m.Groups[defineWithValue.CommentGroup].Value.Trim('*', '/', '!', '<', ' '); if (text == "") { text = null; } else { text = $"{text} ({macro})"; } defineWithValue.FoundDefines.Add(macro); if ((macro.StartsWith("USE_") || macro.EndsWith("_ENABLED")) && (value == "0" || value == "1" || value == "0x1")) { prop = new PropertyEntry.Boolean { Name = text ?? macro, UniqueID = macro, ValueForTrue = "1", ValueForFalse = "0", DefaultValue = value != "0" }; } else if (int.TryParse(value, out var intValue) || (value.StartsWith("0x") && int.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out intValue))) { prop = new PropertyEntry.Integral { Name = text ?? macro, UniqueID = macro, DefaultValue = intValue } } ; else { prop = new PropertyEntry.String { Name = text ?? macro, UniqueID = macro, DefaultValue = value } }; } if (prop != null) { if (group == null) { throw new Exception("Property group could not be parsed. Please double-check " + file); } group.Properties.Add(prop); } } } var template = new ConfigurationFileTemplate { PropertyClasses = new[] { valuelessDefine, defineWithValue }.Select(d => d.ToPropertyClass()).ToArray(), TargetFileName = Path.GetFileName(file), PropertyList = propertyList, UserFriendlyName = "STM32 HAL Configuration", }; return(new ConfigurationFileTemplateEx(template) { TestableHeaderFiles = cf.TestableHeaderFiles, TestableParameters = testableParameters.ToArray(), }); } }
// parser type config static PropertyEntry ParserProperty(string[] pKFile, ref int countline) { string ln, TypeProperty = "none", Name = "", lstHelp = "", Macros = "", DefValue = ""; uint max = UInt32.MaxValue, resParseU; PropertyEntry PropEntry = null; int resParse, min = -1; bool flHelp = false; bool typNoName = false; while (countline < pKFile.Count()) { ln = pKFile[countline]; if (ln.StartsWith("#")) { countline++; continue; } if (!ln.StartsWith("config") && !ln.StartsWith("menuconfig") && Macros == "") { return(null); } if (ln.StartsWith("end") || ln.StartsWith("source") || ln.StartsWith("menu ")) { if (Macros != "")//заполнены поля { countline--; break; } else { return(null); } } Match m = Regex.Match(ln, "^(menuconfig|config|choice)[ ]+([A-Z0-9_]+)"); if (m.Success) { if (TypeProperty != "none")//parsing is done { countline--; break; } if (m.Groups[1].Value != "config" && m.Groups[1].Value != "menuconfig") { countline--; return(null); } Macros = strPrefixConfProperty + m.Groups[2].Value; } if (flHelp) { lstHelp += ln; } else { m = Regex.Match(ln, "^[ \t]+(int|bool|hex|string)[ ]*[\"]?(['\\w0-9_ \\(\\)-]*)[\"]?"); if (m.Success) { TypeProperty = m.Groups[1].Value; if (m.Groups[2].Value == "") { countNoNameProp++; Console.WriteLine(ln); if (false) { Name = Macros; typNoName = true; } else { if (Macros == "ESP32_PHY_MAX_TX_POWER" || Macros == "PHY_ENABLED") { Name = Macros; } else { TypeProperty = "none"; countline++; continue; } // no dublecate } } else { Name = m.Groups[2].Value; } //TypeProperty = m.Groups[1].Value; } else { if (!typNoName) { m = Regex.Match(ln, "^[ \t]+default[\t ]+(['/\"_\\w 0-9-]*)"); if (m.Success) { DefValue = m.Groups[1].Value; } } else { if (ln.Contains("default")) { // flHelp = true; Console.WriteLine(ln); } } m = Regex.Match(ln, "^[ \t]+range[ \t]([\\w\\d]+)[ \t]+([\\w\\d]+)"); if (m.Success) { var minInt = Int32.TryParse(m.Groups[1].Value, out resParse) ? Int32.Parse(m.Groups[1].Value) : 0; var maxInt = UInt32.TryParse(m.Groups[2].Value, out resParseU) ? UInt32.Parse(m.Groups[2].Value) : UInt32.MaxValue; min = ((min < minInt) && (min > -1)) ? min : minInt; max = maxInt; } if (Regex.IsMatch(ln, "^[ \t]+help[ \t]*")) { flHelp = true; } } } countline++; } // save switch (TypeProperty) { case "string": PropEntry = new PropertyEntry.String() { Name = Name, UniqueID = Macros, Description = lstHelp, DefaultValue = DefValue }; break; case "bool": PropEntry = new PropertyEntry.Boolean() { Name = Name, UniqueID = Macros, Description = lstHelp, DefaultValue = DefValue.ToLower().Contains("y") ? true : false }; break; case "int": case "hex": PropEntry = new PropertyEntry.Integral() { Name = Name, UniqueID = Macros, Description = lstHelp, DefaultValue = Int32.TryParse(DefValue, out resParse) ? Int32.Parse(DefValue) : 0, MinValue = (min == -1) ? 0 : min, MaxValue = (min == -1) ? Int32.MaxValue : (int)max }; break; case "none": return(null); default: throw new Exception(" unknow type config"); } return(PropEntry); }