namespace Common; using System; using System.Collections; /* Simple configuration syntax " key = value #comment key = multi line value [Section] key = value " this(String input) ToString(String buffer) SetValue(section, name, value) GetValue(section, name) : StringValue */ class Config { private (StringView, StringView) _latest = ("", ""); private Dictionary> _data = new .() { (new String(""), new .()) //Unsectioned data }; public this(StringView content) { for (var line in content.Split('\n')) _ParseLine(line); } public ~this() { for (var d in _data) DeleteDictionaryAndKeysAndValues!(d.value); DeleteDictionaryAndKeys!(_data); } public void Serialize(String buffer) { buffer.Clear(); for (var entry in _data[""]) { if (!entry.value.Contains('\n')) buffer.Append(scope $"{entry.key} = {entry.value}\n"); else { var parts = entry.value.Split('\n'); buffer.Append(scope $"{entry.key} = {parts.GetNext().Value}\n"); for (var part in parts) buffer.Append(scope $" {part}\n"); } } for (var section in _data) { if (section.key == "") continue; buffer.Append(scope $"[{section.key}]\n"); for (var entry in section.value) { if (!entry.value.Contains('\n')) buffer.Append(scope $"{entry.key} = {entry.value}\n"); else { var parts = entry.value.Split('\n'); buffer.Append(scope $"{entry.key} = {parts.GetNext().Value}\n"); for (var part in parts) buffer.Append(scope $" {part}\n"); } } } while (buffer.EndsWith('\n')) buffer.RemoveFromEnd(1); } public Result GetValue(StringView section, StringView name) { if (!_data.ContainsKeyAlt(section)) return .Err; var dict = _data[scope .(section)]; if (!dict.ContainsKeyAlt(name)) return .Err; return .Ok(dict[scope .(name)]); } public void SetValue(StringView section, StringView name, StringView value) { if (!_data.ContainsKeyAlt(section)) _data.Add(new .(section), new .()); var dict = _data[scope .(section)]; if (!dict.ContainsKeyAlt(name)) { dict.Add(new .(name), new .(value)); return; } dict[scope .(name)].Set(value); } private void _ParseLine(StringView line) { var line; if (line.IsEmpty || line.StartsWith('#') || (line[0] == '\t' && line.Length == 1)) return; if (line.StartsWith('\t')) { if (_latest.0 == "" && _latest.1 == "") return; //This is safe under the assumption, that _latest did not get changed by external uses _data.GetValue(scope .(_latest.0)) .Value.GetValue(scope .(_latest.1)) .Value.Append(scope $"\n{line.Substring(1)}"); return; } if (line.StartsWith('[') && !line.EndsWith(']')) return; else if (line.StartsWith('[') && line.EndsWith(']')) { if (line.Length - 2 < 0) return; var section = new String(line.Substring(1, line.Length - 2)); if (!_data.ContainsKeyAlt(section)) _data.Add(section, new .()); _latest.0 = section; _latest.1 = ""; } if (!line.Contains(" = ")) return; var parts = line.Split(" = "); var name = parts.GetNext(); var text = new String(parts.Remnant); if (_data.GetValue(scope .(_latest.0)) case .Ok(var val)) if (!val.ContainsKeyAlt(name)) { val.Add(new .(name), text); _latest.1 = name; } } }