From 5c911fc08d463914235df6bae68bb9a976ba508e Mon Sep 17 00:00:00 2001 From: "sashakoshka@tebibyte.media" Date: Thu, 3 Oct 2024 19:52:17 -0400 Subject: [PATCH] Add desktop file format stub --- format/desktop_entry/README | 12 +++ format/desktop_entry/desktop_entry.ha | 131 ++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 format/desktop_entry/README create mode 100644 format/desktop_entry/desktop_entry.ha diff --git a/format/desktop_entry/README b/format/desktop_entry/README new file mode 100644 index 0000000..efeebec --- /dev/null +++ b/format/desktop_entry/README @@ -0,0 +1,12 @@ +The desktop_entry module implements the XDG Desktop Entry Specification as +described in (https://specifications.freedesktop.org/desktop-entry-spec/latest). +Since other specifications make use of the basic desktop entry format (but with +different group names, entry requirements, etc.), this module implements: + +1. The generalized format, and +2. A second processing stage to retrieve values relevant to desktop entries and + to validate them. + +This module will attempt to accept malformed files for the purposes of retaining +their underlying representation, and being able to reproduce that representation +when writing updated information to the files. diff --git a/format/desktop_entry/desktop_entry.ha b/format/desktop_entry/desktop_entry.ha new file mode 100644 index 0000000..3b210d1 --- /dev/null +++ b/format/desktop_entry/desktop_entry.ha @@ -0,0 +1,131 @@ +// Represents a file of the generic key/value format used by desktop entries. +// Specification: §3 +type file = struct { + preceeding_lines: []line; + groups: []group; +}; + +// A named group of key/value entries. +// Specification: §3.2 +type group = struct { + name: str; + lines: []line; +} + +// A line in the file, which can be a comment (or a blank line), an entry, or +// a localized entry. +type line = (comment | entry | localized_entry); + +// A comment. +// Specification: §3.1 +type comment = str; + +// A key/value pair. +// Specification: §3.3 +type entry = struct { + key: str; + value: value; +}; + +// A localized entry. +// Specification: §5 +type localized_entry struct { + key: str; + value: value; + locale: locale::locale; +}; + +// An entry value. Values that reference memory (such as [[str]]) are borrowed +// from the [[file]]. These may be free'd or overwritten when other functions in +// this module are called, so [[value_dup]] is required to extend its lifetime. +export type value = (str, bool, f32); + +// Gets a non-localized value from a file. If the group does not exist, or the +// group exists but the key isn't in it, it returns void. +export fn file_get(fil: *file, group_name: str, key: str) (value | void) { + let grou = match (file_find_group(fil, group_name)) { + case index: size => yield &file.groups[index]; + case void => return void; + }; + let lin = match (group_find_entry(grou, key)) { + case index: size => yield &grou.lines[index]; + case void => return void; + }; + match (lin) { + case entr: entry => return entr.value; + case => abort(); + }; +}; + +// Gets a localized value from a file. If the group does not exist, or the group +// exists but the key isnt in it, it returns void. If the key is in the group +// but is not localized to the specified locale, the non-localized value is +// returned. +export fn file_get_localized( + fil: *file, + group_name: str, + key: str, + local: locale, +) (value | void) { + let grou = match (file_find_group(fil, group_name)) { + case index: size => yield &file.groups[index]; + case void => return void; + }; + let lin = match (group_find_localized_entry(grou, key, local)) { + case index: size => yield &grou.lines[index]; + case void => return void; + }; + match (lin) { + case entr: localized_entry => return entr.value; + case entr: entry => return entr.value; + case => abort(); + }; +}; + +export fn file_add + +export fn file_add_localized + +export fn file_remove + +export fn file_remove_localized + +export fn file_encode + +export fn file_finish + +fn file_find_group (fil *file, group_name str): (size | void) = { + let index = 0; + for (let grou .. file.groups) { + if (strings::compare(group.name, group_name) == 0) { + return index; + } + index ++; + } +} + +fn group_find_entry (grou *group, key str): (size | void) { + let index = 0; + for (let lin .. grou.lines) { + match (lin) { + case entr: entry => + if (strings::compare(entry.key, entr) == 0) { + return index; + } + case => void ; + } + index ++; + } +} + +// Duplicates a [[value]]. Use [[value_finish]] to get rid of it. +export fn value_dup(valu: value): value = match (valu) { +case let valu: str => yield strings.dup(valu); +case => yield valu; +}; + +// Frees an [[entry]] previously duplicated with [[entry_dup]]. +export fn value_finish(valu: value): void = match (valu) { +case let valu: str => free(valu); +case => void; +};