/// <summary> /// Append definitions recognized in a header file. /// </summary> /// <param name="path"> /// A <see cref="System.String"/> that specified the path of the header file. /// </param> public void AppendHeader(string path) { if (path == null) { throw new ArgumentNullException("path"); } string headerText; // Read the whole header using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { using (StreamReader sr = new StreamReader(fs)) { headerText = sr.ReadToEnd(); } } // Remove comments string inlineComment = @"//(.*?)\r?\n"; string blockComment = @"/\*(.*?)\*/"; headerText = Regex.Replace(headerText, String.Format("{0}|{1}", inlineComment, blockComment), delegate(Match match) { if (match.Value.StartsWith("/*")) { return(String.Empty); } if (match.Value.StartsWith("//")) { return(Environment.NewLine); } return(match.Value); }, RegexOptions.Singleline); // Extract C preprocessor #define directives string defineDirective = @"#define (?<Symbol>[\w\d_]+) +(?<Value>.*)\r?\n"; EnumerantBlock definesBlock = new EnumerantBlock(); definesBlock.Group = "Defines"; headerText = Regex.Replace(headerText, defineDirective, delegate(Match match) { // Collect symbol/value if (match.Value.StartsWith("#define ")) { Enumerant enumerant = new Enumerant(); enumerant.Name = match.Groups["Symbol"].Value; enumerant.Value = match.Groups["Value"].Value; enumerant.ParentEnumerantBlock = definesBlock; definesBlock.Enums.Add(enumerant); // Collect enumerant _Enumerants.Add(enumerant); return(String.Empty); } return(match.Value); }, RegexOptions.Multiline); // Remove no more necessary C preprocessor string preprocessorDirective = @"#(if|ifndef|else|endif|define|include) ?.*\r?\n"; headerText = Regex.Replace(headerText, preprocessorDirective, String.Empty); // Remove new lines headerText = Regex.Replace(headerText, @"\r?\n", String.Empty); // Remove structures typedefs string structTypedef = @"typedef struct ?\{(.*?)\}( +?)(.*?);"; headerText = Regex.Replace(headerText, structTypedef, String.Empty); // Remove multiple spaces headerText = Regex.Replace(headerText, @" +", " "); // Extract extern "C" scope string externBlock = "extern \"C\" {"; if (headerText.StartsWith(externBlock)) { headerText = headerText.Substring(externBlock.Length, headerText.Length - externBlock.Length - 1); } // Split into statements string[] statements = Regex.Split(headerText, ";"); foreach (string statement in statements) { Match match; // Parse enumeration block if ((match = Regex.Match(statement, @"typedef enum ?\{(?<Enums>.*)\}( +?)(?<Tag>[\w\d_]+)")).Success) { string name = match.Groups["Tag"].Value; if (Regex.IsMatch(name, "WF(C|D)boolean")) { continue; } #region Enumeration EnumerantBlock enumerantBlock = new EnumerantBlock(); enumerantBlock.Group = "WFD_VERSION_1_0"; EnumerantGroup enumerantGroup = new EnumerantGroup(); enumerantGroup.Name = name; // Parse enumerations string[] enumValues = Regex.Split(match.Groups["Enums"].Value, ","); for (int i = 0; i < enumValues.Length; i++) { string enumValue = enumValues[i].Trim(); if ((match = Regex.Match(enumValue, @"(?<Name>(\w|_)+) = (?<Value>.*)")).Success) { Enumerant enumerant = new Enumerant(); enumerant.Name = match.Groups["Name"].Value; enumerant.Value = match.Groups["Value"].Value; enumerant.ParentEnumerantBlock = enumerantBlock; enumerantBlock.Enums.Add(enumerant); enumerantGroup.Enums.Add(enumerant); // Collect enumerant _Enumerants.Add(enumerant); } } _Groups.Add(enumerantGroup); #endregion continue; } else if ((match = Regex.Match(statement, @"WF(D|C)_API_CALL (?<Return>.*) WF(D|C)_APIENTRY (?<Name>.*)\((?<Args>.*)\) WF(D|C)_APIEXIT")).Success) { #region Command Command command = new Command(); command.Prototype = new CommandPrototype(); command.Prototype.Type = match.Groups["Return"].Value; command.Prototype.Name = match.Groups["Name"].Value; string[] args = Regex.Split(match.Groups["Args"].Value, ","); for (int i = 0; i < args.Length; i++) { string arg = args[i].Trim(); // '*' denotes types, not names arg = arg.Replace(" **", "** "); arg = arg.Replace(" *", "* "); if ((match = Regex.Match(arg, @"(?<Type>(\w|_|\*)+) (?<Name>[\w\d_]+)$")).Success) { CommandParameter commandParameter = new CommandParameter(); commandParameter.Name = match.Groups["Name"].Value; commandParameter.Type = match.Groups["Type"].Value; command.Parameters.Add(commandParameter); } else { throw new InvalidOperationException(String.Format("unable to parse argument '{0}'", arg)); } } _Commands.Add(command); #endregion } } Feature wfdVersion1 = new Feature(); FeatureCommand wfdVersion1Feature = new FeatureCommand(); wfdVersion1.Name = String.Format("{0}_VERSION_1_0", Class.ToUpperInvariant()); wfdVersion1.Api = Class.ToLowerInvariant(); wfdVersion1.Number = "1.0"; wfdVersion1.Requirements.Add(wfdVersion1Feature); wfdVersion1Feature.Enums.AddRange(_Enumerants.ConvertAll(delegate(Enumerant input) { return(new FeatureCommand.Item(input.Name)); })); wfdVersion1Feature.Commands.AddRange(_Commands.ConvertAll(delegate(Command input) { return(new FeatureCommand.Item(input.Prototype.Name)); })); _Features.Add(wfdVersion1); }
/// <summary> /// Append definitions recognized in a header file. /// </summary> /// <param name="path"> /// A <see cref="System.String"/> that specified the path of the header file. /// </param> public void AppendHeader(string path, string headerFeatureName) { if (path == null) { throw new ArgumentNullException(nameof(path)); } string headerText; // Read the whole header using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { using (StreamReader sr = new StreamReader(fs)) { headerText = sr.ReadToEnd(); } } // Remove comments string inlineComment = @"//(.*?)\r?\n"; string blockComment = @"/\*(.*?)\*/"; headerText = Regex.Replace(headerText, String.Format("{0}|{1}", inlineComment, blockComment), delegate(Match match) { if (match.Value.StartsWith("/*")) { return(String.Empty); } if (match.Value.StartsWith("//")) { return(Environment.NewLine); } return(match.Value); }, RegexOptions.Singleline); // Extract C preprocessor #define directives string defineDirective = @"#define (?<Symbol>[\w\d_]+) +(?<Value>.*)\r?\n"; EnumerantBlock definesBlock = new EnumerantBlock(); definesBlock.Group = "Defines"; headerText = Regex.Replace(headerText, defineDirective, delegate(Match match) { // Collect symbol/value if (match.Value.StartsWith("#define ")) { Enumerant enumerant = new Enumerant(); // Replace enumeration macros string enumDefinition = ReplaceEnumMacros(match.Groups["Value"].Value.Trim()); // Replace constants in enumeration value enumDefinition = ReplaceEnumConstants(enumDefinition); enumerant.Name = match.Groups["Symbol"].Value.Trim(); enumerant.Value = enumDefinition; enumerant.ParentEnumerantBlock = definesBlock; bool useDefine = true; if (enumerant.Value.StartsWith("__")) { useDefine = false; } if (enumerant.Value.StartsWith("{") && enumerant.Value.EndsWith("}")) { useDefine = false; } if (useDefine) { definesBlock.Enums.Add(enumerant); // Collect enumerant _Enumerants.Add(enumerant); } return(String.Empty); } return(match.Value); }, RegexOptions.Multiline); // Remove no more necessary C preprocessor string preprocessorDirective = @"#(if|ifndef|else|endif|define|include) ?.*\r?\n"; headerText = Regex.Replace(headerText, preprocessorDirective, String.Empty); // Remove new lines headerText = Regex.Replace(headerText, @"\r?\n", String.Empty); // Remove structures typedefs string structTypedef = @"typedef struct ?\{(.*?)\}( +?)(.*?);"; headerText = Regex.Replace(headerText, structTypedef, String.Empty); // Remove multiple spaces headerText = Regex.Replace(headerText, @" +", " "); // Extract extern "C" scope string externBlock = "extern \"C\" {"; if (headerText.StartsWith(externBlock)) { headerText = headerText.Substring(externBlock.Length, headerText.Length - externBlock.Length - 1); } // Split into statements string[] statements = Regex.Split(headerText, ";"); foreach (string statement in statements) { Match match; // Parse enumeration block if ((match = Regex.Match(statement, @"(typedef )?enum(?<Name> [\w\d_]+)? ?\{(?<Enums>.*)\}(?<Tag> +?[\w\d_]+)?")).Success) { string name; if (match.Groups["Tag"].Success) { name = match.Groups["Tag"].Value.Trim(); } else if (match.Groups["Name"].Success) { name = match.Groups["Name"].Value.Trim(); } else { throw new InvalidOperationException("unable to determine name of enum"); } if (Regex.IsMatch(name, "WF(C|D)boolean")) { continue; } #region Enumeration // Skip enumeration if required CommandFlagsDatabase.EnumerantItem enumItem = CommandFlagsDatabase.FindEnumerant(name); if (enumItem != null && enumItem.Disable) { continue; } EnumerantBlock enumerantBlock = new EnumerantBlock(); enumerantBlock.Group = headerFeatureName; EnumerantGroup enumerantGroup = new EnumerantGroup(); enumerantGroup.Name = name; // Override name if (enumItem != null && enumItem.Alias != null) { enumerantGroup.Name = enumItem.Alias; } // Replace enumeration macros string enumDefinition = ReplaceEnumMacros(match.Groups["Enums"].Value); // Replace constants in enumeration value enumDefinition = ReplaceEnumConstants(enumDefinition); // Parse enumerations string[] enumValues = Regex.Split(enumDefinition, ","); for (int i = 0; i < enumValues.Length; i++) { string enumValue = enumValues[i].Trim(); if ((match = Regex.Match(enumValue, @"(?<Name>(\w|_)+)\s*=\s*(?<Value>.*)")).Success) { Enumerant enumerant = new Enumerant(); enumerant.Name = match.Groups["Name"].Value; enumerant.Value = match.Groups["Value"].Value.Trim(); enumerant.ParentEnumerantBlock = enumerantBlock; enumerantBlock.Enums.Add(enumerant); enumerantGroup.Enums.Add(enumerant); // Collect enumerant _Enumerants.Add(enumerant); } } _Groups.Add(enumerantGroup); #endregion continue; } else if ((match = Regex.Match(statement, CommandExportRegex + @"(?<Return>.*) " + CommandCallConventionRegex + @"(?<Name>.*)\((?<Args>.*)\)" + CommandExitRegex)).Success) { #region Command Command command = new Command(); command.Prototype = new CommandPrototype(); command.Prototype.Type = match.Groups["Return"].Value; command.Prototype.Name = match.Groups["Name"].Value; string[] args = Regex.Split(match.Groups["Args"].Value, ","); for (int i = 0; i < args.Length; i++) { string arg = args[i].Trim(); if (arg == String.Empty) { break; } // '*' denotes types, not names arg = arg.Replace(" **", "** "); arg = arg.Replace(" *", "* "); if ((match = Regex.Match(arg, @"(const +)?(?<Type>(\w|_|\* (const)?|\*)+) +(?<Name>[\w\d_]+)(?<ArraySize>\[([\w\d_]+)?\])?$")).Success) { string arraySize = match.Groups["ArraySize"].Success ? match.Groups["ArraySize"].Value : null; CommandParameter commandParameter = new CommandParameter(); commandParameter.Name = match.Groups["Name"].Value; commandParameter.Type = arraySize != null ? match.Groups["Type"].Value + "*" : match.Groups["Type"].Value; command.Parameters.Add(commandParameter); } else if (arg == "...") { CommandParameter commandParameter = new CommandParameter(); commandParameter.Name = "vaArgs"; commandParameter.Type = "IntPtr"; command.Parameters.Add(commandParameter); } else { throw new InvalidOperationException(String.Format("unable to parse argument '{0}'", arg)); } } _Commands.Add(command); #endregion } } Feature headerFeature = _Features.Find(delegate(Feature item) { return(item.Name == headerFeatureName); }); if (headerFeature == null) { headerFeature = new Feature(); headerFeature.Name = headerFeatureName; headerFeature.Api = Class.ToLowerInvariant(); _Features.Add(headerFeature); } FeatureCommand headerFeatureCommand = new FeatureCommand(); headerFeature.Requirements.Add(headerFeatureCommand); headerFeatureCommand.Enums.AddRange(_Enumerants.ConvertAll(delegate(Enumerant input) { return(new FeatureCommand.Item(input.Name)); })); headerFeatureCommand.Commands.AddRange(_Commands.ConvertAll(delegate(Command input) { return(new FeatureCommand.Item(input.Prototype.Name)); })); }