diff options
Diffstat (limited to 'hscript')
-rw-r--r-- | hscript/meta.cc | 72 | ||||
-rw-r--r-- | hscript/meta.hh | 9 | ||||
-rw-r--r-- | hscript/script.cc | 63 |
3 files changed, 123 insertions, 21 deletions
diff --git a/hscript/meta.cc b/hscript/meta.cc index 7e8cfe8..e5e0ba4 100644 --- a/hscript/meta.cc +++ b/hscript/meta.cc @@ -13,6 +13,7 @@ #include <assert.h> #include <fstream> #include <regex> +#include <set> #include <sstream> #ifdef HAS_INSTALL_ENV # include <unistd.h> @@ -179,6 +180,77 @@ Key *PkgInstall::parseFromData(const std::string &data, int lineno, int *errors, } +/* All ISO 639-1 language codes. + * Source: https://www.loc.gov/standards/iso639-2/ISO-639-2_utf-8.txt + * Python to construct table: + * >>> f = open('ISO-639-2_utf-8.txt') + * >>> x = csv.reader(f, delimiter='|') + * >>> langs = [lang[2] for lang in iter(x) if lang != ''] + * >>> print('"' + '", "'.join(langs) + '", "C."') + */ +const std::set<std::string> valid_langs = { + "aa", "ab", "af", "ak", "sq", "am", "ar", "an", "hy", "as", "av", "ae", + "ay", "az", "ba", "bm", "eu", "be", "bn", "bh", "bi", "bs", "br", "bg", + "my", "ca", "ch", "ce", "zh", "cu", "cv", "kw", "co", "cr", "cs", "da", + "dv", "nl", "dz", "en", "eo", "et", "ee", "fo", "fj", "fi", "fr", "fy", + "ff", "ka", "de", "gd", "ga", "gl", "gv", "el", "gn", "gu", "ht", "ha", + "he", "hz", "hi", "ho", "hr", "hu", "ig", "is", "io", "ii", "iu", "ie", + "ia", "id", "ik", "it", "jv", "ja", "kl", "kn", "ks", "kr", "kk", "km", + "ki", "rw", "ky", "kv", "kg", "ko", "kj", "ku", "lo", "la", "lv", "li", + "ln", "lt", "lb", "lu", "lg", "mk", "mh", "ml", "mi", "mr", "ms", "mg", + "mt", "mn", "na", "nv", "nr", "nd", "ng", "ne", "nn", "nb", "no", "ny", + "oc", "oj", "or", "om", "os", "pa", "fa", "pi", "pl", "pt", "ps", "qu", + "rm", "ro", "rn", "ru", "sg", "sa", "si", "sk", "sl", "se", "sm", "sn", + "sd", "so", "st", "es", "sc", "sr", "ss", "su", "sw", "sv", "ty", "ta", + "tt", "te", "tg", "tl", "th", "bo", "ti", "to", "tn", "ts", "tk", "tr", + "tw", "ug", "uk", "ur", "uz", "ve", "vi", "vo", "cy", "wa", "wo", "xh", + "yi", "yo", "za", "zu", "C." +}; + + +Key *Language::parseFromData(const std::string &data, int lineno, int *errors, + int *warnings) { + if(data.length() < 2 || + valid_langs.find(data.substr(0, 2)) == valid_langs.end()) { + if(errors) *errors += 1; + output_error("installfile:" + std::to_string(lineno), + "language: invalid language specified", + "language must be a valid ISO 639-1 language code"); + return nullptr; + } + + /* We know a valid language appears, but is it real? */ + if(data.length() > 2) { + /* data[1] is . if language is C.UTF-8 */ + if(data[2] != '_' && data[1] != '.') { + if(errors) *errors += 1; + output_error("installfile:" + std::to_string(lineno), + "language: invalid language specified", + "language must be a valid ISO 639-1 language code, " + "optionally followed by '_' and a country code"); + return nullptr; + } + /* we don't really care about the country code, but we do care about + * codeset - we (via musl) *only* support UTF-8. */ + std::string::size_type dot = data.find_first_of('.'); + if(dot != std::string::npos && data.substr(dot+1, 5) != "UTF-8") { + if(errors) *errors += 1; + output_error("installfile:" + std::to_string(lineno), + "language: invalid language specified", + "you cannot specify a non-UTF-8 codeset"); + return nullptr; + } + } + + return new Language(lineno, data); +} + + +bool Language::execute(ScriptOptions) const { + return false; +} + + Key *Firmware::parseFromData(const std::string &data, int lineno, int *errors, int *warnings) { bool value; diff --git a/hscript/meta.hh b/hscript/meta.hh index 8a50576..7dc3f68 100644 --- a/hscript/meta.hh +++ b/hscript/meta.hh @@ -45,6 +45,13 @@ public: }; class Language : public StringKey { +private: + Language(int _line, const std::string &my_lang) : + StringKey(_line, my_lang) {} +public: + static Key *parseFromData(const std::string &data, int lineno, int *errors, + int *warnings); + bool execute(ScriptOptions) const override; }; class Keymap : public StringKey { @@ -63,7 +70,7 @@ class Timezone : public StringKey { class Repository : public StringKey { private: - Repository(int _line, const std::string my_url) : + Repository(int _line, const std::string &my_url) : StringKey(_line, my_url) {} public: static Key *parseFromData(const std::string &data, int lineno, int *errors, diff --git a/hscript/script.cc b/hscript/script.cc index 33003bf..69a46cc 100644 --- a/hscript/script.cc +++ b/hscript/script.cc @@ -88,8 +88,8 @@ struct Script::ScriptPrivate { std::set<std::string> packages; /*! The root shadow line. */ std::unique_ptr<RootPassphrase> rootpw; - /*! Target system's mountpoints. */ - std::vector< std::unique_ptr<Mount> > mounts; + /*! The system language. */ + std::unique_ptr<Language> lang; /*! Network addressing configuration */ std::vector< std::unique_ptr<NetAddress> > addresses; @@ -103,6 +103,8 @@ struct Script::ScriptPrivate { /*! Disk identification keys */ std::vector< std::unique_ptr<DiskId> > diskids; + /*! Target system's mountpoints. */ + std::vector< std::unique_ptr<Mount> > mounts; #ifdef NON_LIBRE_FIRMWARE std::unique_ptr<Firmware> firmware; @@ -119,18 +121,6 @@ struct Script::ScriptPrivate { int *errors, int *warnings, const ScriptOptions &opts) { if(key_name == "network") { return store_network(obj, lineno, errors, warnings, opts); - } else if(key_name == "hostname") { - return store_hostname(obj, lineno, errors, warnings, opts); - } else if(key_name == "pkginstall") { - return store_pkginstall(obj, lineno, errors, warnings, opts); - } else if(key_name == "rootpw") { - return store_rootpw(obj, lineno, errors, warnings, opts); - } else if(key_name == "firmware") { - return store_firmware(obj, lineno, errors, warnings, opts); - } else if(key_name == "mount") { - std::unique_ptr<Mount> mount(dynamic_cast<Mount *>(obj)); - this->mounts.push_back(std::move(mount)); - return true; } else if(key_name == "netaddress") { std::unique_ptr<NetAddress> addr(dynamic_cast<NetAddress *>(obj)); this->addresses.push_back(std::move(addr)); @@ -139,14 +129,20 @@ struct Script::ScriptPrivate { std::unique_ptr<NetSSID> ssid(dynamic_cast<NetSSID *>(obj)); this->ssids.push_back(std::move(ssid)); return true; + } else if(key_name == "hostname") { + return store_hostname(obj, lineno, errors, warnings, opts); + } else if(key_name == "pkginstall") { + return store_pkginstall(obj, lineno, errors, warnings, opts); + } else if(key_name == "rootpw") { + return store_rootpw(obj, lineno, errors, warnings, opts); + } else if(key_name == "language") { + return store_lang(obj, lineno, errors, warnings, opts); + } else if(key_name == "firmware") { + return store_firmware(obj, lineno, errors, warnings, opts); } else if(key_name == "repository") { std::unique_ptr<Repository> repo(dynamic_cast<Repository *>(obj)); this->repos.push_back(std::move(repo)); return true; - } else if(key_name == "diskid") { - std::unique_ptr<DiskId> diskid(dynamic_cast<DiskId *>(obj)); - this->diskids.push_back(std::move(diskid)); - return true; } else if(key_name == "username") { return store_username(obj, lineno, errors, warnings, opts); } else if(key_name == "useralias") { @@ -157,6 +153,14 @@ struct Script::ScriptPrivate { return store_usericon(obj, lineno, errors, warnings, opts); } else if(key_name == "usergroups") { return store_usergroups(obj, lineno, errors, warnings, opts); + } else if(key_name == "diskid") { + std::unique_ptr<DiskId> diskid(dynamic_cast<DiskId *>(obj)); + this->diskids.push_back(std::move(diskid)); + return true; + } else if(key_name == "mount") { + std::unique_ptr<Mount> mount(dynamic_cast<Mount *>(obj)); + this->mounts.push_back(std::move(mount)); + return true; } else { return false; } @@ -241,6 +245,18 @@ struct Script::ScriptPrivate { #endif } + bool store_lang(Keys::Key *obj, int lineno, int *errors, int *, + ScriptOptions) { + if(this->lang) { + DUPLICATE_ERROR(this->lang, std::string("language"), + this->lang->value()) + return false; + } + std::unique_ptr<Language> l(dynamic_cast<Language *>(obj)); + this->lang = std::move(l); + return true; + } + bool store_username(Keys::Key *obj, int lineno, int *errors, int *, ScriptOptions) { if(accounts.size() >= 255) { @@ -527,9 +543,16 @@ bool Script::validate() const { /* REQ: Runner.Validate.rootpw */ if(!this->internal->rootpw->validate(this->opts)) failures++; - /* language */ + /* REQ: Runner.Validate.language */ + if(internal->lang && !internal->lang->validate(this->opts)) failures++; + /* keymap */ - /* firmware */ + +#ifdef NON_LIBRE_FIRMWARE + /* REQ: Runner.Validate.firmware */ + if(!this->internal->firmware->validate(this->opts)) failures++; +#endif + /* timezone */ /* REQ: Script.repository */ |