Made the desktop entry format more... convenient to work with
This commit is contained in:
parent
b90f0c5378
commit
cabc7c1e19
@ -3,7 +3,7 @@ use strings;
|
|||||||
|
|
||||||
// A line in the file, which can be a comment (or a blank line), an entry, or
|
// A line in the file, which can be a comment (or a blank line), an entry, or
|
||||||
// a localized entry.
|
// a localized entry.
|
||||||
export type line = (blank | comment | entry | localized_entry);
|
export type line = (blank | comment | group_header | entry);
|
||||||
|
|
||||||
// A blank line.
|
// A blank line.
|
||||||
// Specification: §3.1
|
// Specification: §3.1
|
||||||
@ -17,35 +17,27 @@ export type comment = str;
|
|||||||
// Specification: §3.2
|
// Specification: §3.2
|
||||||
export type group_header = str;
|
export type group_header = str;
|
||||||
|
|
||||||
// A key/value pair.
|
// An entry in a desktop file.
|
||||||
// Specification: §3.3
|
// Specification: §3.3, §5
|
||||||
export type entry = (str, str);
|
export type entry = struct {
|
||||||
|
group: str,
|
||||||
// A localized key/value pair.
|
key: str,
|
||||||
// Specification: §5
|
value: str,
|
||||||
export type localized_entry = (str, str, locale::locale);
|
locale: locale::locale,
|
||||||
|
};
|
||||||
|
|
||||||
// Duplicates an [[entry]]. Use [[entry_finish]] to get rid of it.
|
// Duplicates an [[entry]]. Use [[entry_finish]] to get rid of it.
|
||||||
export fn entry_dup(entr: entry) entry = (
|
export fn entry_dup(entr: entry) entry = entry {
|
||||||
strings::dup(entr.0),
|
group = strings::dup(entr.group),
|
||||||
strings::dup(entr.1));
|
key = strings::dup(entr.key),
|
||||||
|
value = strings::dup(entr.value),
|
||||||
|
locale = locale::dup(entr.locale),
|
||||||
|
};
|
||||||
|
|
||||||
// Frees memory associated with an [[entry]].
|
// Frees memory associated with an [[entry]].
|
||||||
export fn entry_finish(entr: entry) void = {
|
export fn entry_finish(entr: entry) void = {
|
||||||
free(entr.0);
|
free(entr.group);
|
||||||
free(entr.1);
|
free(entr.key);
|
||||||
};
|
free(entr.value);
|
||||||
|
locale::finish(entr.locale);
|
||||||
// Duplicates a [[localized_entry]]. Use [[localized_entry_finish]] to get rid
|
|
||||||
// of it.
|
|
||||||
export fn localized_entry_dup(entr: localized_entry) localized_entry = (
|
|
||||||
strings::dup(entr.0),
|
|
||||||
strings::dup(entr.1),
|
|
||||||
locale::dup(entr.2));
|
|
||||||
|
|
||||||
// Frees memory associated with an [[localized_entry]].
|
|
||||||
export fn localized_entry_finish(entr: localized_entry) void = {
|
|
||||||
free(entr.0);
|
|
||||||
free(entr.1);
|
|
||||||
locale::finish(entr.2);
|
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ export type invalid_group_header = !void;
|
|||||||
// Returned when a malformed entry is encountered while parsing.
|
// Returned when a malformed entry is encountered while parsing.
|
||||||
export type invalid_entry = !void;
|
export type invalid_entry = !void;
|
||||||
|
|
||||||
// Returned when ASCII text was expected, while parsing, but something else was
|
// Returned when ASCII text was expected while parsing, but something else was
|
||||||
// given.
|
// given.
|
||||||
export type invalid_ascii = !void;
|
export type invalid_ascii = !void;
|
||||||
|
|
||||||
|
@ -8,8 +8,7 @@ use strings;
|
|||||||
|
|
||||||
export type scanner = struct {
|
export type scanner = struct {
|
||||||
scanner: bufio::scanner,
|
scanner: bufio::scanner,
|
||||||
entry: entry,
|
group: str,
|
||||||
localized_entry: localized_entry,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Creates a desktop entry file scanner. Use [[next]] to read lines. The caller
|
// Creates a desktop entry file scanner. Use [[next]] to read lines. The caller
|
||||||
@ -41,30 +40,25 @@ export fn next(this: *scanner) (line | io::EOF | error) = {
|
|||||||
|
|
||||||
} else if (strings::hasprefix(text, '[')) {
|
} else if (strings::hasprefix(text, '[')) {
|
||||||
// group header
|
// group header
|
||||||
return parse_group_header(text)?;
|
let header = parse_group_header(text)?;
|
||||||
|
free(this.group);
|
||||||
|
this.group = header: str;
|
||||||
|
return header;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// key/value pair
|
// key/value pair
|
||||||
let (key, valu, local) = parse_entry(text)?;
|
let entry = parse_entry(text)?;
|
||||||
|
entry.group = this.group;
|
||||||
match (local) {
|
return entry;
|
||||||
case let local: locale::locale =>
|
|
||||||
localized_entry_finish(this.localized_entry);
|
|
||||||
this.localized_entry = (key, valu, local);
|
|
||||||
return this.localized_entry;
|
|
||||||
case void =>
|
|
||||||
entry_finish(this.entry);
|
|
||||||
this.entry = (key, valu);
|
|
||||||
return this.entry;
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: have next_entry that auto-skips over blank lines and comments
|
||||||
|
|
||||||
// Frees resources associated with a [[scanner]].
|
// Frees resources associated with a [[scanner]].
|
||||||
export fn finish(this: *scanner) void = {
|
export fn finish(this: *scanner) void = {
|
||||||
bufio::finish(&this.scanner);
|
bufio::finish(&this.scanner);
|
||||||
entry_finish(this.entry);
|
free(this.group);
|
||||||
};
|
};
|
||||||
|
|
||||||
// memory is borrowed from the input
|
// memory is borrowed from the input
|
||||||
@ -80,26 +74,32 @@ fn parse_group_header(text: str) (group_header | error) = {
|
|||||||
return text: group_header;
|
return text: group_header;
|
||||||
};
|
};
|
||||||
|
|
||||||
// memory must be freed by the caller
|
// memory is borrowed from the input
|
||||||
fn parse_entry(line: str) ((str, str, (locale::locale | void)) | error) = {
|
fn parse_entry(line: str) (entry | error) = {
|
||||||
if (!strings::contains(line, '=')) return invalid_entry;
|
if (!strings::contains(line, '=')) return invalid_entry;
|
||||||
let (key, valu) = strings::cut(line, "=");
|
let (key, valu) = strings::cut(line, "=");
|
||||||
key = strings::ltrim(strings::rtrim(key));
|
key = strings::ltrim(strings::rtrim(key));
|
||||||
if (!validate_entry_key(key)) return invalid_entry;
|
if (!validate_entry_key(key)) return invalid_entry;
|
||||||
|
|
||||||
let local: (locale::locale | void) = void;
|
|
||||||
let (key, local_string) = strings::cut(key, "[");
|
let (key, local_string) = strings::cut(key, "[");
|
||||||
if (local_string != "") {
|
let local = if (local_string != "") {
|
||||||
|
yield locale::c;
|
||||||
|
} else {
|
||||||
local_string = strings::rtrim(local_string, ']');
|
local_string = strings::rtrim(local_string, ']');
|
||||||
if (!validate_entry_locale(local_string)) return invalid_entry;
|
if (!validate_entry_locale(local_string)) return invalid_entry;
|
||||||
|
|
||||||
local = match(locale::parse(local_string)) {
|
yield match(locale::parse(local_string)) {
|
||||||
case let local: locale::locale => yield local;
|
case let local: locale::locale => yield local;
|
||||||
case locale::invalid => return invalid_entry;
|
case locale::invalid => return invalid_entry;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return (strings::dup(key), strings::dup(valu), local);
|
return entry {
|
||||||
|
key = key,
|
||||||
|
value = valu,
|
||||||
|
locale = local,
|
||||||
|
...
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fn validate_entry_key(key: str) bool = {
|
fn validate_entry_key(key: str) bool = {
|
||||||
|
Loading…
Reference in New Issue
Block a user