Esempio n. 1
0
        //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);
        }
Esempio n. 2
0
        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()
            });
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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(),
            });
        }
    }
Esempio n. 5
0
        // 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);
        }