Tidying.
[libdcp.git] / src / language_tag.cc
index 4ac90507101b3c20ae0caa356c6e83a4261b040d..c2e81869ed133cbb8a10a5eeed5d6a980e3a471f 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    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>
 
 
@@ -47,23 +51,28 @@ using std::pair;
 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 {};
 }
 
 
@@ -143,7 +152,7 @@ LanguageTag::to_string () const
                throw LanguageTagError("No language set up");
        }
 
-       string s = _language->subtag();
+       auto s = _language->subtag();
 
        if (_script) {
                s += "-" + _script->subtag();
@@ -153,11 +162,11 @@ LanguageTag::to_string () const
                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();
        }
 
@@ -204,7 +213,7 @@ check_for_duplicates (vector<T> const& subtags, dcp::LanguageTag::SubtagType typ
        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()));
                }
@@ -216,7 +225,7 @@ check_for_duplicates (vector<T> const& subtags, dcp::LanguageTag::SubtagType typ
 void
 LanguageTag::set_variants (vector<VariantSubtag> variants)
 {
-       check_for_duplicates (variants, VARIANT);
+       check_for_duplicates (variants, SubtagType::VARIANT);
        _variants = variants;
 }
 
@@ -235,7 +244,7 @@ LanguageTag::add_extlang (ExtlangSubtag extlang)
 void
 LanguageTag::set_extlangs (vector<ExtlangSubtag> extlangs)
 {
-       check_for_duplicates (extlangs, EXTLANG);
+       check_for_duplicates (extlangs, SubtagType::EXTLANG);
        _extlangs = extlangs;
 }
 
@@ -249,30 +258,30 @@ LanguageTag::description () const
 
        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;
        }
@@ -281,40 +290,23 @@ LanguageTag::description () const
 }
 
 
-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;
 }
 
 
@@ -322,19 +314,19 @@ string
 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
@@ -383,26 +375,26 @@ dcp::operator<< (ostream& os, dcp::LanguageTag const& tag)
 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;
@@ -413,30 +405,74 @@ optional<LanguageTag::SubtagData>
 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);
+}
+
+