/// <summary> /// Reads the key and value. /// </summary> /// <param name="currentSection">The current section.</param> /// <param name="currentLine">The current line.</param> /// <param name="lineRaw">The line raw.</param> /// <param name="lineNumber">The line number.</param> /// <param name="append">if set to <c>true</c> [append].</param> /// <exception cref="ConfigParserException">Arrays must start from a new line and not after the key! /// or</exception> /// <exception cref="NotImplementedException"></exception> private void ReadKeyAndValue(ref ConfigSection currentSection, ref ConfigLine currentLine, string lineRaw, int lineNumber, bool append = false, bool forceIncludeKey = false) { if (null != currentLine && !append) { BackupCurrentLine(ref currentSection, ref currentLine, lineNumber); } if (append && null == currentLine) { throw new ConfigParserException("You are trying to append value to a null line!", lineNumber); } var keyMatch = Settings.KeyMatcher.Match(lineRaw); var keyName = keyMatch.Groups["key"]?.Value; var separator = (string.IsNullOrWhiteSpace(keyMatch.Groups["separator"]?.Value)) ? Settings.KeyValueSeparator : keyMatch.Groups["separator"]?.Value; if (!forceIncludeKey && keyMatch.Success && keyMatch.Captures.Count > 0) { lineRaw = lineRaw.Substring(keyMatch.Captures[0].Value.Length); } var valueMatch = Settings.ValueMatcher.Match(lineRaw); var value = valueMatch.Groups["value"]?.Value; switch (Settings.MultiLineValues) { case var _ when Settings.MultiLineValues.HasFlag(MultiLineValues.QuoteDelimitedValues): if (!string.IsNullOrEmpty(value)) { if (Equals('"', value.First())) { value = value.Substring(1); } if (Equals('"', value.Last())) { value = value.Remove(value.Length - 1); } } break; case var _ when Settings.MultiLineValues.HasFlag(MultiLineValues.NotAllowed) || Settings.MultiLineValues.HasFlag(MultiLineValues.Simple): // Do nothing add with quotes if any break; default: throw new ConfigParserException("Unknown key=value situation detected!", lineNumber); } try { if (append) { currentLine.Content = $"{currentLine.Content}{Settings.NewLine}{value}"; } else { currentLine = new ConfigKeyValue <object>(keyName, separator, value, lineNumber); } } catch (Exception ex) { throw new ConfigParserException($"Failed to parse the following line: '{lineRaw}'", lineNumber, ex); } }
/// <summary> /// Reads the specified configuration content. /// </summary> /// <param name="configContent">Content of the configuration.</param> /// <exception cref="ArgumentException">configContent</exception> private void Read(string configContent) { if (string.IsNullOrWhiteSpace(configContent)) { throw new ArgumentException(nameof(configContent)); } using var stringReader = new StringReader(configContent); string lineRaw; var lineNumber = 0; ConfigSection currentSection = null; ConfigLine currentLine = null; while (null != (lineRaw = stringReader.ReadLine())) { lineNumber++; switch (lineRaw) { case var _ when string.IsNullOrWhiteSpace(lineRaw): ReadEmptyLine(ref currentSection, ref currentLine, lineRaw, lineNumber); continue; case var _ when ConfigParserSettings.SectionMatcher.IsMatch(lineRaw): ReadSection(ref currentSection, ref currentLine, lineRaw, lineNumber); break; case var _ when Settings.CommentMatcher.IsMatch(lineRaw): ReadComment(ref currentSection, ref currentLine, lineRaw, lineNumber); break; case var _ when Settings.KeyMatcher.IsMatch(lineRaw): if (!Settings.MultiLineValues.HasFlag(MultiLineValues.NotAllowed) && IsKeyLikeArrayValue(currentLine?.Content, lineRaw)) { ReadKeyAndValue(ref currentSection, ref currentLine, lineRaw, lineNumber, append: true, forceIncludeKey: true); } else { ReadKeyAndValue(ref currentSection, ref currentLine, lineRaw, lineNumber); } break; // Multi-line + allow value-less option on case var _ when Settings.ValueMatcher.IsMatch(lineRaw) && currentLine != null && Settings.KeyMatcher.IsMatch(currentLine.ToString()) && Settings.MultiLineValues.HasFlag(MultiLineValues.AllowValuelessKeys) && Settings.MultiLineValues.HasFlag(MultiLineValues.Simple) && ConfigLine.IndentationMatcher.IsMatch(lineRaw) && !Equals(currentLine.Indentation, ConfigLine.IndentationMatcher.Match(lineRaw).Value): AppendValueToKey(ref currentSection, ref currentLine, lineRaw, lineNumber); break; case var _ when Settings.ValueMatcher.IsMatch(lineRaw): if (Settings.MultiLineValues.HasFlag(MultiLineValues.AllowValuelessKeys)) { ReadValuelessKey(ref currentSection, ref currentLine, lineRaw, lineNumber); } else { AppendValueToKey(ref currentSection, ref currentLine, lineRaw, lineNumber); } break; default: throw new ConfigParserException("Unknown element found!", lineNumber); } } if (null != currentLine) { BackupCurrentLine(ref currentSection, ref currentLine, lineNumber); } if (null != currentSection) { sections.Add(currentSection.SectionName, currentSection); } }