mirror of https://github.com/buggins/dlangui.git
194 lines
5.8 KiB
D
194 lines
5.8 KiB
D
/**
|
|
* Reading and writing ini-like files used in some Unix systems and Freedesktop specifications.
|
|
* ini-like is informal name for the file format that look like this:
|
|
* ---
|
|
# Comment
|
|
[Group name]
|
|
Key=Value
|
|
# Comment inside group
|
|
AnotherKey=Value
|
|
|
|
[Another group]
|
|
Key=English value
|
|
Key[fr_FR]=Francais value
|
|
|
|
* ---
|
|
* Authors:
|
|
* $(LINK2 https://github.com/FreeSlave, Roman Chistokhodov)
|
|
* Copyright:
|
|
* Roman Chistokhodov, 2015-2016
|
|
* License:
|
|
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
|
* See_Also:
|
|
* $(LINK2 http://standards.freedesktop.org/desktop-entry-spec/latest/index.html, Desktop Entry Specification)
|
|
*/
|
|
|
|
module inilike;
|
|
|
|
public import inilike.common;
|
|
public import inilike.range;
|
|
public import inilike.file;
|
|
|
|
unittest
|
|
{
|
|
import std.exception;
|
|
|
|
final class DesktopEntry : IniLikeGroup
|
|
{
|
|
this() {
|
|
super("Desktop Entry");
|
|
}
|
|
protected:
|
|
@trusted override void validateKey(string key, string value) const {
|
|
if (!isValidDesktopFileKey(key)) {
|
|
throw new IniLikeEntryException("key is invalid", groupName(), key, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
final class DesktopFile : IniLikeFile
|
|
{
|
|
//Options to manage .ini like file reading
|
|
static struct DesktopReadOptions
|
|
{
|
|
IniLikeFile.ReadOptions baseOptions;
|
|
|
|
alias baseOptions this;
|
|
|
|
bool skipExtensionGroups;
|
|
bool ignoreUnknownGroups;
|
|
bool skipUnknownGroups;
|
|
}
|
|
|
|
@trusted this(IniLikeReader)(IniLikeReader reader, DesktopReadOptions options = DesktopReadOptions.init)
|
|
{
|
|
_options = options;
|
|
super(reader, null, options.baseOptions);
|
|
enforce(_desktopEntry !is null, new IniLikeReadException("No \"Desktop Entry\" group", 0));
|
|
}
|
|
|
|
@safe override bool removeGroup(string groupName) nothrow {
|
|
if (groupName == "Desktop Entry") {
|
|
return false;
|
|
}
|
|
return super.removeGroup(groupName);
|
|
}
|
|
|
|
protected:
|
|
@trusted override IniLikeGroup createGroupByName(string groupName)
|
|
{
|
|
if (groupName == "Desktop Entry") {
|
|
_desktopEntry = new DesktopEntry();
|
|
return _desktopEntry;
|
|
} else if (groupName.startsWith("X-")) {
|
|
if (_options.skipExtensionGroups) {
|
|
return null;
|
|
}
|
|
return createEmptyGroup(groupName);
|
|
} else {
|
|
if (_options.ignoreUnknownGroups) {
|
|
if (_options.skipUnknownGroups) {
|
|
return null;
|
|
} else {
|
|
return createEmptyGroup(groupName);
|
|
}
|
|
} else {
|
|
throw new IniLikeException("Unknown group");
|
|
}
|
|
}
|
|
}
|
|
|
|
inout(DesktopEntry) desktopEntry() inout {
|
|
return _desktopEntry;
|
|
}
|
|
|
|
private:
|
|
DesktopEntry _desktopEntry;
|
|
DesktopReadOptions _options;
|
|
}
|
|
|
|
string contents =
|
|
`# First comment
|
|
[Desktop Entry]
|
|
Key=Value
|
|
# Comment in group`;
|
|
DesktopFile.DesktopReadOptions options;
|
|
|
|
auto df = new DesktopFile(iniLikeStringReader(contents), options);
|
|
assert(!df.removeGroup("Desktop Entry"));
|
|
assert(!df.removeGroup("NonExistent"));
|
|
assert(df.group("Desktop Entry") !is null);
|
|
assert(df.desktopEntry() !is null);
|
|
assert(equal(df.desktopEntry().byIniLine(), [IniLikeLine.fromKeyValue("Key", "Value"), IniLikeLine.fromComment("# Comment in group")]));
|
|
assert(equal(df.leadingComments(), ["# First comment"]));
|
|
|
|
assertThrown(df.desktopEntry().writeEntry("$Invalid", "Valid value"));
|
|
|
|
IniLikeEntryException entryException;
|
|
try {
|
|
df.desktopEntry().writeEntry("$Invalid", "Valid value");
|
|
} catch(IniLikeEntryException e) {
|
|
entryException = e;
|
|
}
|
|
assert(entryException !is null);
|
|
df.desktopEntry().writeEntry("$Invalid", "Valid value", IniLikeGroup.InvalidKeyPolicy.save);
|
|
assert(df.desktopEntry().value("$Invalid") == "Valid value");
|
|
|
|
assert(df.desktopEntry().appendValue("Another$Invalid", "Valid value", IniLikeGroup.InvalidKeyPolicy.skip).isNull());
|
|
assert(df.desktopEntry().setValue("Another$Invalid", "Valid value", IniLikeGroup.InvalidKeyPolicy.skip) is null);
|
|
assert(df.desktopEntry().value("Another$Invalid") is null);
|
|
|
|
contents =
|
|
`[X-SomeGroup]
|
|
Key=Value`;
|
|
|
|
auto thrown = collectException!IniLikeReadException(new DesktopFile(iniLikeStringReader(contents)));
|
|
assert(thrown !is null);
|
|
assert(thrown.lineNumber == 0);
|
|
|
|
contents =
|
|
`[Desktop Entry]
|
|
Valid=Key
|
|
$=Invalid`;
|
|
|
|
thrown = collectException!IniLikeReadException(new DesktopFile(iniLikeStringReader(contents)));
|
|
assert(thrown !is null);
|
|
assert(thrown.entryException !is null);
|
|
assert(thrown.entryException.key == "$");
|
|
assert(thrown.entryException.value == "Invalid");
|
|
|
|
options = DesktopFile.DesktopReadOptions.init;
|
|
options.invalidKeyPolicy = IniLikeGroup.InvalidKeyPolicy.skip;
|
|
assertNotThrown(new DesktopFile(iniLikeStringReader(contents), options));
|
|
|
|
contents =
|
|
`[Desktop Entry]
|
|
Name=Name
|
|
[Unknown]
|
|
Key=Value`;
|
|
|
|
assertThrown(new DesktopFile(iniLikeStringReader(contents)));
|
|
|
|
options = DesktopFile.DesktopReadOptions.init;
|
|
options.ignoreUnknownGroups = true;
|
|
|
|
assertNotThrown(df = new DesktopFile(iniLikeStringReader(contents), options));
|
|
assert(df.group("Unknown") !is null);
|
|
|
|
options.skipUnknownGroups = true;
|
|
df = new DesktopFile(iniLikeStringReader(contents), options);
|
|
assert(df.group("Unknown") is null);
|
|
|
|
contents =
|
|
`[Desktop Entry]
|
|
Name=Name1
|
|
[X-Extension]
|
|
Name=Name2`;
|
|
|
|
options = DesktopFile.DesktopReadOptions.init;
|
|
options.skipExtensionGroups = true;
|
|
|
|
df = new DesktopFile(iniLikeStringReader(contents), options);
|
|
assert(df.group("X-Extension") is null);
|
|
}
|