/*
- Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2020-2021 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
*/
+/** @file src/language_tag.cc
+ * @brief LanguageTag class
+ */
+
+
#include "compose.hpp"
#include "dcp_assert.h"
#include "exceptions.h"
#include "language_tag.h"
#include <boost/algorithm/string.hpp>
-#include <boost/foreach.hpp>
#include <string>
using std::string;
using std::vector;
using boost::optional;
+using boost::algorithm::trim;
using namespace dcp;
-#include "language_tag_lists.cc"
+static vector<LanguageTag::SubtagData> language_list;
+static vector<LanguageTag::SubtagData> variant_list;
+static vector<LanguageTag::SubtagData> region_list;
+static vector<LanguageTag::SubtagData> script_list;
+static vector<LanguageTag::SubtagData> extlang_list;
static
optional<LanguageTag::SubtagData>
-find_in_list (LanguageTag::SubtagData* list, int length, string subtag)
+find_in_list (vector<LanguageTag::SubtagData> const& list, string subtag)
{
- for (int i = 0; i < length; ++i) {
- if (list[i].subtag == subtag) {
- return list[i];
+ for (auto const& i: list) {
+ if (boost::iequals(i.subtag, subtag)) {
+ return i;
}
}
- return optional<LanguageTag::SubtagData>();
+ return {};
}
throw LanguageTagError("No language set up");
}
- string s = _language->subtag();
+ auto s = _language->subtag();
if (_script) {
s += "-" + _script->subtag();
s += "-" + _region->subtag();
}
- BOOST_FOREACH (VariantSubtag i, _variants) {
+ for (auto i: _variants) {
s += "-" + i.subtag();
}
- BOOST_FOREACH (ExtlangSubtag i, _extlangs) {
+ for (auto i: _extlangs) {
s += "-" + i.subtag();
}
vector<T> sorted = subtags;
sort (sorted.begin(), sorted.end());
optional<T> last;
- BOOST_FOREACH (T const& i, sorted) {
+ for (auto const& i: sorted) {
if (last && i == *last) {
throw LanguageTagError (String::compose("Duplicate %1 subtag %2", dcp::LanguageTag::subtag_type_name(type), i.subtag()));
}
void
LanguageTag::set_variants (vector<VariantSubtag> variants)
{
- check_for_duplicates (variants, VARIANT);
+ check_for_duplicates (variants, SubtagType::VARIANT);
_variants = variants;
}
void
LanguageTag::set_extlangs (vector<ExtlangSubtag> extlangs)
{
- check_for_duplicates (extlangs, EXTLANG);
+ check_for_duplicates (extlangs, SubtagType::EXTLANG);
_extlangs = extlangs;
}
string d;
- BOOST_FOREACH (VariantSubtag const& i, _variants) {
- optional<SubtagData> variant = get_subtag_data (VARIANT, i.subtag());
+ for (auto const& i: _variants) {
+ optional<SubtagData> variant = get_subtag_data (SubtagType::VARIANT, i.subtag());
DCP_ASSERT (variant);
d += variant->description + " dialect of ";
}
- optional<SubtagData> language = get_subtag_data (LANGUAGE, _language->subtag());
+ auto language = get_subtag_data (SubtagType::LANGUAGE, _language->subtag());
DCP_ASSERT (language);
d += language->description;
if (_script) {
- optional<SubtagData> script = get_subtag_data (SCRIPT, _script->subtag());
+ auto script = get_subtag_data (SubtagType::SCRIPT, _script->subtag());
DCP_ASSERT (script);
d += " written using the " + script->description + " script";
}
if (_region) {
- optional<SubtagData> region = get_subtag_data (REGION, _region->subtag());
+ auto region = get_subtag_data (SubtagType::REGION, _region->subtag());
DCP_ASSERT (region);
d += " for " + region->description;
}
- BOOST_FOREACH (ExtlangSubtag const& i, _extlangs) {
- optional<SubtagData> extlang = get_subtag_data (EXTLANG, i.subtag());
+ for (auto const& i: _extlangs) {
+ auto extlang = get_subtag_data (SubtagType::EXTLANG, i.subtag());
DCP_ASSERT (extlang);
d += ", " + extlang->description;
}
}
-vector<LanguageTag::SubtagData>
+vector<LanguageTag::SubtagData> const &
LanguageTag::get_all (SubtagType type)
{
- vector<LanguageTag::SubtagData> all;
-
switch (type) {
- case LANGUAGE:
- for (size_t i = 0; i < sizeof(language_list) / sizeof(LanguageTag::SubtagData); ++i) {
- all.push_back (language_list[i]);
- }
- break;
- case SCRIPT:
- for (size_t i = 0; i < sizeof(script_list) / sizeof(LanguageTag::SubtagData); ++i) {
- all.push_back (script_list[i]);
- }
- break;
- case REGION:
- for (size_t i = 0; i < sizeof(region_list) / sizeof(LanguageTag::SubtagData); ++i) {
- all.push_back (region_list[i]);
- }
- break;
- case VARIANT:
- for (size_t i = 0; i < sizeof(variant_list) / sizeof(LanguageTag::SubtagData); ++i) {
- all.push_back (variant_list[i]);
- }
- break;
- case EXTLANG:
- for (size_t i = 0; i < sizeof(extlang_list) / sizeof(LanguageTag::SubtagData); ++i) {
- all.push_back (extlang_list[i]);
- }
- break;
+ case SubtagType::LANGUAGE:
+ return language_list;
+ case SubtagType::SCRIPT:
+ return script_list;
+ case SubtagType::REGION:
+ return region_list;
+ case SubtagType::VARIANT:
+ return variant_list;
+ case SubtagType::EXTLANG:
+ return extlang_list;
}
- return all;
+ return language_list;
}
LanguageTag::subtag_type_name (SubtagType type)
{
switch (type) {
- case LANGUAGE:
+ case SubtagType::LANGUAGE:
return "Language";
- case SCRIPT:
+ case SubtagType::SCRIPT:
return "Script";
- case REGION:
+ case SubtagType::REGION:
return "Region";
- case VARIANT:
+ case SubtagType::VARIANT:
return "Variant";
- case EXTLANG:
+ case SubtagType::EXTLANG:
return "Extended";
}
- return "";
+ return {};
}
bool
vector<pair<LanguageTag::SubtagType, LanguageTag::SubtagData> >
LanguageTag::subtags () const
{
- vector<pair<SubtagType, SubtagData> > s;
+ vector<pair<SubtagType, SubtagData>> s;
if (_language) {
- s.push_back (make_pair(LANGUAGE, *get_subtag_data(LANGUAGE, _language->subtag())));
+ s.push_back (make_pair(SubtagType::LANGUAGE, *get_subtag_data(SubtagType::LANGUAGE, _language->subtag())));
}
if (_script) {
- s.push_back (make_pair(SCRIPT, *get_subtag_data(SCRIPT, _script->subtag())));
+ s.push_back (make_pair(SubtagType::SCRIPT, *get_subtag_data(SubtagType::SCRIPT, _script->subtag())));
}
if (_region) {
- s.push_back (make_pair(REGION, *get_subtag_data(REGION, _region->subtag())));
+ s.push_back (make_pair(SubtagType::REGION, *get_subtag_data(SubtagType::REGION, _region->subtag())));
}
- BOOST_FOREACH (VariantSubtag const& i, _variants) {
- s.push_back (make_pair(VARIANT, *get_subtag_data(VARIANT, i.subtag())));
+ for (auto const& i: _variants) {
+ s.push_back (make_pair(SubtagType::VARIANT, *get_subtag_data(SubtagType::VARIANT, i.subtag())));
}
- BOOST_FOREACH (ExtlangSubtag const& i, _extlangs) {
- s.push_back (make_pair(EXTLANG, *get_subtag_data(EXTLANG, i.subtag())));
+ for (auto const& i: _extlangs) {
+ s.push_back (make_pair(SubtagType::EXTLANG, *get_subtag_data(SubtagType::EXTLANG, i.subtag())));
}
return s;
LanguageTag::get_subtag_data (LanguageTag::SubtagType type, string subtag)
{
switch (type) {
- case dcp::LanguageTag::LANGUAGE:
- return find_in_list(language_list, sizeof(language_list) / sizeof(LanguageTag::SubtagData), subtag);
- case dcp::LanguageTag::SCRIPT:
- return find_in_list(script_list, sizeof(script_list) / sizeof(LanguageTag::SubtagData), subtag);
- case dcp::LanguageTag::REGION:
- return find_in_list(region_list, sizeof(region_list) / sizeof(LanguageTag::SubtagData), subtag);
- case dcp::LanguageTag::VARIANT:
- return find_in_list(variant_list, sizeof(variant_list) / sizeof(LanguageTag::SubtagData), subtag);
- case dcp::LanguageTag::EXTLANG:
- return find_in_list(extlang_list, sizeof(extlang_list) / sizeof(LanguageTag::SubtagData), subtag);
+ case SubtagType::LANGUAGE:
+ return find_in_list(language_list, subtag);
+ case SubtagType::SCRIPT:
+ return find_in_list(script_list, subtag);
+ case SubtagType::REGION:
+ return find_in_list(region_list, subtag);
+ case SubtagType::VARIANT:
+ return find_in_list(variant_list, subtag);
+ case SubtagType::EXTLANG:
+ return find_in_list(extlang_list, subtag);
}
- return optional<LanguageTag::SubtagData>();
+ return {};
}
optional<string>
LanguageTag::get_subtag_description (LanguageTag::SubtagType type, string subtag)
{
- optional<SubtagData> data = get_subtag_data (type, subtag);
+ auto data = get_subtag_data (type, subtag);
if (!data) {
- return optional<string>();
+ return {};
}
return data->description;
}
+
+void
+load_language_tag_list (boost::filesystem::path tags_directory, string name, vector<LanguageTag::SubtagData>& list)
+{
+ auto f = fopen_boost (tags_directory / name, "r");
+ if (!f) {
+ throw FileError ("Could not open tags file", tags_directory / name, errno);
+ }
+ char buffer[512];
+
+ int i = 0;
+ while (!feof(f)) {
+ char* r = fgets (buffer, sizeof(buffer), f);
+ if (r == 0) {
+ break;
+ }
+ string a = buffer;
+ trim (a);
+ r = fgets (buffer, sizeof(buffer), f);
+ if (r == 0) {
+ fclose (f);
+ throw FileError ("Bad tags file", tags_directory / name, -1);
+ }
+ string b = buffer;
+ trim (b);
+ list.push_back (LanguageTag::SubtagData(a, b));
+ ++i;
+ }
+
+ fclose (f);
+}
+
+
+void
+dcp::load_language_tag_lists (boost::filesystem::path tags_directory)
+{
+ load_language_tag_list (tags_directory, "language", language_list);
+ load_language_tag_list (tags_directory, "variant", variant_list);
+ load_language_tag_list (tags_directory, "region", region_list);
+ load_language_tag_list (tags_directory, "script", script_list);
+ load_language_tag_list (tags_directory, "extlang", extlang_list);
+}
+
+