From cabc7c1e19c979ec434ef31693e83870d9ebd5f6 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Sat, 19 Oct 2024 16:15:23 -0400 Subject: [PATCH] Made the desktop entry format more... convenient to work with --- format/desktop_entry/desktop_entry.ha | 46 +++++++++++-------------- format/desktop_entry/error.ha | 2 +- format/desktop_entry/scan.ha | 48 +++++++++++++-------------- 3 files changed, 44 insertions(+), 52 deletions(-) diff --git a/format/desktop_entry/desktop_entry.ha b/format/desktop_entry/desktop_entry.ha index 2fc17a7..6e34edc 100644 --- a/format/desktop_entry/desktop_entry.ha +++ b/format/desktop_entry/desktop_entry.ha @@ -3,7 +3,7 @@ use strings; // A line in the file, which can be a comment (or a blank line), an entry, or // a localized entry. -export type line = (blank | comment | entry | localized_entry); +export type line = (blank | comment | group_header | entry); // A blank line. // Specification: §3.1 @@ -17,35 +17,27 @@ export type comment = str; // Specification: §3.2 export type group_header = str; -// A key/value pair. -// Specification: §3.3 -export type entry = (str, str); - -// A localized key/value pair. -// Specification: §5 -export type localized_entry = (str, str, locale::locale); +// An entry in a desktop file. +// Specification: §3.3, §5 +export type entry = struct { + group: str, + key: str, + value: str, + locale: locale::locale, +}; // Duplicates an [[entry]]. Use [[entry_finish]] to get rid of it. -export fn entry_dup(entr: entry) entry = ( - strings::dup(entr.0), - strings::dup(entr.1)); +export fn entry_dup(entr: entry) entry = entry { + group = strings::dup(entr.group), + key = strings::dup(entr.key), + value = strings::dup(entr.value), + locale = locale::dup(entr.locale), +}; // Frees memory associated with an [[entry]]. export fn entry_finish(entr: entry) void = { - free(entr.0); - free(entr.1); -}; - -// 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); + free(entr.group); + free(entr.key); + free(entr.value); + locale::finish(entr.locale); }; diff --git a/format/desktop_entry/error.ha b/format/desktop_entry/error.ha index fc5e349..99f63f1 100644 --- a/format/desktop_entry/error.ha +++ b/format/desktop_entry/error.ha @@ -17,7 +17,7 @@ export type invalid_group_header = !void; // Returned when a malformed entry is encountered while parsing. 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. export type invalid_ascii = !void; diff --git a/format/desktop_entry/scan.ha b/format/desktop_entry/scan.ha index e856138..1e9ea92 100644 --- a/format/desktop_entry/scan.ha +++ b/format/desktop_entry/scan.ha @@ -7,9 +7,8 @@ use memio; use strings; export type scanner = struct { - scanner: bufio::scanner, - entry: entry, - localized_entry: localized_entry, + scanner: bufio::scanner, + group: str, }; // 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, '[')) { // group header - return parse_group_header(text)?; + let header = parse_group_header(text)?; + free(this.group); + this.group = header: str; + return header; } else { // key/value pair - let (key, valu, local) = parse_entry(text)?; - - match (local) { - 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; - }; + let entry = parse_entry(text)?; + entry.group = this.group; + return entry; }; - }; +// TODO: have next_entry that auto-skips over blank lines and comments + // Frees resources associated with a [[scanner]]. export fn finish(this: *scanner) void = { bufio::finish(&this.scanner); - entry_finish(this.entry); + free(this.group); }; // memory is borrowed from the input @@ -80,26 +74,32 @@ fn parse_group_header(text: str) (group_header | error) = { return text: group_header; }; -// memory must be freed by the caller -fn parse_entry(line: str) ((str, str, (locale::locale | void)) | error) = { +// memory is borrowed from the input +fn parse_entry(line: str) (entry | error) = { if (!strings::contains(line, '=')) return invalid_entry; let (key, valu) = strings::cut(line, "="); key = strings::ltrim(strings::rtrim(key)); if (!validate_entry_key(key)) return invalid_entry; - let local: (locale::locale | void) = void; 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, ']'); 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 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 = {