From e8af5d01d729f60f55b6e228623f38c3b27eca08 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Sat, 12 Oct 2024 23:34:57 -0400 Subject: [PATCH] Desktop entry module almost compiles --- format/desktop_entry/desktop_entry.ha | 48 ++++++++++++++------ format/desktop_entry/parse.ha | 64 ++++++++++++++------------- 2 files changed, 68 insertions(+), 44 deletions(-) diff --git a/format/desktop_entry/desktop_entry.ha b/format/desktop_entry/desktop_entry.ha index f2b006e..3aaed68 100644 --- a/format/desktop_entry/desktop_entry.ha +++ b/format/desktop_entry/desktop_entry.ha @@ -31,22 +31,22 @@ export type comment = str; // Specification: §3.3 export type entry = struct { key: str, - value: value, + value: str, }; // A localized key/value pair. // Specification: §5 export type localized_entry = struct { key: str, - value: value, + value: str, locale: locale::locale, }; // 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) = { +export fn file_get(fil: *file, group_name: str, key: str) (str | void) = { let grou = match (file_find_group(fil, group_name)) { - case let index: size => yield &fil.groups[index]; + case let index: size => yield fil.groups[index]; case void => return void; }; let lin = match (group_find_entry(grou, key)) { @@ -70,9 +70,9 @@ export fn file_get_localized( group_name: str, key: str, local: locale::locale, -) (value | void) = { +) (str | void) = { let grou = match (file_find_group(fil, group_name)) { - case let index: size => yield &fil.groups[index]; + case let index: size => yield fil.groups[index]; case void => return void; }; let lin = match (group_find_localized_entry(grou, key, local)) { @@ -103,15 +103,37 @@ export fn file_get_localized( //export fn file_encode // Frees memory associated with a [[file]]. -export fn file_finish(fil *file) void = { - for (let lin .. file.lines) { +export fn file_finish(fil: *file) void = { + for (let lin .. fil.preceeding_lines) { line_finish(lin); }; - free(file.lines); - for (let grou .. file.groups) { + free(fil.preceeding_lines); + for (let grou .. fil.groups) { group_finish(grou); }; - free(file.groups); + free(fil.groups); +}; + +// Frees memory associated with a [[line]]. +export fn line_finish(lin: line) void = match (lin) { +case let lin: comment => + free(lin); +case let lin: entry => + free(lin.key); + free(lin.value); +case let lin: localized_entry => + free(lin.key); + free(lin.value); + locale::finish(lin.locale); +case => void; +}; + +// Frees memory associated with a [[group]]. +export fn group_finish(grou: group) void = { + for (let lin .. grou.lines) { + line_finish(lin); + }; + free(grou.lines); }; fn file_find_group(fil: *file, group_name: str) (size | void) = { @@ -124,7 +146,7 @@ fn file_find_group(fil: *file, group_name: str) (size | void) = { }; }; -fn group_find_entry(grou: *group, key: str) (size | void) = { +fn group_find_entry(grou: group, key: str) (size | void) = { let index = 0z; for (let lin .. grou.lines) { match (lin) { @@ -138,7 +160,7 @@ fn group_find_entry(grou: *group, key: str) (size | void) = { }; }; -fn group_find_localized_entry(grou: *group, key: str, local: locale::locale) (size | void) = { +fn group_find_localized_entry(grou: group, key: str, local: locale::locale) (size | void) = { // The matching is done as follows. If LC_MESSAGES is of the form // lang_COUNTRY.ENCODING@MODIFIER, then it will match a key of the form // lang_COUNTRY@MODIFIER. If such a key does not exist, it will attempt diff --git a/format/desktop_entry/parse.ha b/format/desktop_entry/parse.ha index eced0a0..d734bc0 100644 --- a/format/desktop_entry/parse.ha +++ b/format/desktop_entry/parse.ha @@ -1,14 +1,16 @@ -use encoding; use bufio; +use encoding::utf8; use io; +use locale; use memio; +use strings; // Parses a [[file]]. The result must be freed using [[file_finish]]. -export fn file_parse(in: io::stream) (file | error | io::error | utf8::invalid) = { - let scanner = bufio::newscanner(in); - defer bufio::finish(scanner); +export fn file_parse(in: io::stream) !(file | error | io::error | utf8::invalid) = { + let scanner = bufio::newscanner(&in); + defer bufio::finish(&scanner); - let fil: file = { ... }; + let fil = file { ... }; for (true) { let text = match (bufio::scan_line(&scanner)) { @@ -17,35 +19,35 @@ export fn file_parse(in: io::stream) (file | error | io::error | utf8::invalid) case let err: io::EOF => break; case let err: (io::error | utf8::invalid) => - file_finish(fil); + file_finish(&fil); return err; }; if (text == "") { // blank line - file_append_line(fil, blank); + file_append_line(&fil, blank); - } else if (strings::has_prefix(text, '#')) { + } else if (strings::hasprefix(text, '#')) { // comment let text = strings::dup(strings::ltrim(text, '#')); - file_append_line(fil, text: comment); + file_append_line(&fil, text: comment); - } else if (strings::has_prefix(text, '[')) { + } else if (strings::hasprefix(text, '[')) { // group header let name = strings::dup(parse_group_header(text)?); - file_append_group(fil, name); + file_append_group(&fil, name); } else { // key/value pair - let (key, valu, local) = match (parse_entry()) { - case let result: (str, value, (locale::locale | void)) => + let (key, valu, local) = match (parse_entry(text)) { + case let result: (str, str, (locale::locale | void)) => yield result; case let err: error => - file_finish(fil); + file_finish(&fil); return err; }; - file_append_line(fil, match (local) { + file_append_line(&fil, match (local) { case let local: locale::locale => yield localized_entry { key = key, @@ -63,9 +65,9 @@ export fn file_parse(in: io::stream) (file | error | io::error | utf8::invalid) return fil; }; -fn file_append_line(fil: *file, lin: line) = { +fn file_append_line(fil: *file, lin: line) void = { if (len(fil.groups) > 0) { - append(fil.groups[len(fil.groups - 1)].lines, lin); + append(fil.groups[len(fil.groups) - 1].lines, lin); } else { append(fil.preceeding_lines, lin); }; @@ -73,37 +75,37 @@ fn file_append_line(fil: *file, lin: line) = { // memory is borrowed from the input fn parse_group_header(text: str) (str | error) = { - if !strings::has_prefix(text, '[') || !strings::has_suffix(text, ']') { - return error::INVALID_GROUP_HEADER; + if (!strings::hasprefix(text, '[') || !strings::hassuffix(text, ']')) { + return invalid_group_header; }; text = strings::rtrim(strings::ltrim(text, '['), ']'); - if strings::contains(text, '[', ']') { - return error::INVALID_GROUP_HEADER; + if (strings::contains(text, '[', ']')) { + return invalid_group_header; }; return text; }; // memory must be freed by the caller fn parse_entry(line: str) ((str, str, (locale::locale | void)) | error) = { - if !strings::contains(line, '=') return error::INVALID_ENTRY; - let key, valu_string = strings::cut(line, '='); + 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 error::INVALID_ENTRY; + if (!validate_entry_key(key)) return invalid_entry; - let local = (locale::locale | void) = void; - let (key, local_string) = strings::cut(key, '['); + let local: (locale::locale | void) = void; + let (key, local_string) = strings::cut(key, "["); if (local_string != "") { - local_string = locale(strings::rtrim(local, ']')); - if (!validate_entry_locale(local_string)) return error::INVALID_ENTRY; + local_string = locale(strings::rtrim(local, "]")); + if (!validate_entry_locale(local_string)) return invalid_entry; local = match(local_string) { - case let local = locale::locale => yield local; - case errors::invalid => return error::INVALID_ENTRY; + case let local: locale::locale => yield local; + case errors::invalid => return invalid_entry; }; }; - return strings::dup(key), strings::dup(valu), local; + return (strings::dup(key), strings::dup(valu), local); }; fn validate_entry_key(key: str) bool = {