0ad/source/third_party/tinygettext/src/dictionary_manager.cpp
Yves fd3d335265 Sacrifices a goat to the gods of insanity.
Fixes random crashes on Windows due to differences of STL types on the
binary level between different static libraries.
The differences are caused by the definition of _HAS_ITERATOR_DEBUGGING
and _SECURE_SCL in lib/precompiled.h.
All our engine static libs use precompiled headers but we didn't use
them for tinygettext because they aren't needed (except for these two
defines).
I've decided to add precompiled headers to tinygettext too instead of
just copying these defines. That should cause less headaches in the
future.

This was SVN commit r14983.
2014-04-24 20:05:48 +00:00

244 lines
5.8 KiB
C++

// tinygettext - A gettext replacement that works directly on .po files
// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "precompiled.h"
#include "dictionary_manager.hpp"
#include <memory>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <algorithm>
#include "log_stream.hpp"
#include "po_parser.hpp"
#include "unix_file_system.hpp"
namespace tinygettext {
static bool has_suffix(const std::string& lhs, const std::string rhs)
{
if (lhs.length() < rhs.length())
return false;
else
return lhs.compare(lhs.length() - rhs.length(), rhs.length(), rhs) == 0;
}
DictionaryManager::DictionaryManager(const std::string& charset_) :
dictionaries(),
search_path(),
charset(charset_),
use_fuzzy(true),
current_language(),
current_dict(0),
empty_dict(),
filesystem(new UnixFileSystem)
{
}
DictionaryManager::~DictionaryManager()
{
for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
{
delete i->second;
}
}
void
DictionaryManager::clear_cache()
{
for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
{
delete i->second;
}
dictionaries.clear();
current_dict = 0;
}
Dictionary&
DictionaryManager::get_dictionary()
{
if (current_dict)
{
return *current_dict;
}
else
{
if (current_language)
{
current_dict = &get_dictionary(current_language);
return *current_dict;
}
else
{
return empty_dict;
}
}
}
Dictionary&
DictionaryManager::get_dictionary(const Language& language)
{
//log_debug << "Dictionary for language \"" << spec << "\" requested" << std::endl;
//log_debug << "...normalized as \"" << lang << "\"" << std::endl;
assert(language);
Dictionaries::iterator i = dictionaries.find(language);
if (i != dictionaries.end())
{
return *i->second;
}
else // Dictionary for languages lang isn't loaded, so we load it
{
//log_debug << "get_dictionary: " << lang << std::endl;
Dictionary* dict = new Dictionary(charset);
dictionaries[language] = dict;
for (SearchPath::reverse_iterator p = search_path.rbegin(); p != search_path.rend(); ++p)
{
std::vector<std::string> files = filesystem->open_directory(*p);
std::string best_filename;
int best_score = 0;
for(std::vector<std::string>::iterator filename = files.begin(); filename != files.end(); filename++)
{
// check if filename matches requested language
if (has_suffix(*filename, ".po"))
{ // ignore anything that isn't a .po file
Language po_language = Language::from_env(filename->substr(0, filename->size()-3));
if (!po_language)
{
log_warning << *filename << ": warning: ignoring, unknown language" << std::endl;
}
else
{
int score = Language::match(language, po_language);
if (score > best_score)
{
best_score = score;
best_filename = *filename;
}
}
}
}
if (!best_filename.empty())
{
std::string pofile = *p + "/" + best_filename;
try
{
std::auto_ptr<std::istream> in = filesystem->open_file(pofile);
if (!in.get())
{
log_error << "error: failure opening: " << pofile << std::endl;
}
else
{
POParser::parse(pofile, *in, *dict);
}
}
catch(std::exception& e)
{
log_error << "error: failure parsing: " << pofile << std::endl;
log_error << e.what() << "" << std::endl;
}
}
}
return *dict;
}
}
std::set<Language>
DictionaryManager::get_languages()
{
std::set<Language> languages;
for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p)
{
std::vector<std::string> files = filesystem->open_directory(*p);
for(std::vector<std::string>::iterator file = files.begin(); file != files.end(); ++file)
{
if (has_suffix(*file, ".po"))
{
languages.insert(Language::from_env(file->substr(0, file->size()-3)));
}
}
}
return languages;
}
void
DictionaryManager::set_language(const Language& language)
{
if (current_language != language)
{
current_language = language;
current_dict = 0;
}
}
Language
DictionaryManager::get_language() const
{
return current_language;
}
void
DictionaryManager::set_charset(const std::string& charset_)
{
clear_cache(); // changing charset invalidates cache
charset = charset_;
}
void
DictionaryManager::set_use_fuzzy(bool t)
{
clear_cache();
use_fuzzy = t;
}
bool
DictionaryManager::get_use_fuzzy() const
{
return use_fuzzy;
}
void
DictionaryManager::add_directory(const std::string& pathname)
{
clear_cache(); // adding directories invalidates cache
search_path.push_back(pathname);
}
void
DictionaryManager::set_filesystem(std::auto_ptr<FileSystem> filesystem_)
{
filesystem = filesystem_;
}
} // namespace tinygettext
/* EOF */