00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "fennel/common/CommonPreamble.h"
00024 #include "fennel/common/ResourceBundle.h"
00025
00026 #include <algorithm>
00027 #include <cstdlib>
00028 #include <fstream>
00029 #include <map>
00030 #include <set>
00031 #include <string>
00032 #include <sstream>
00033
00034 #include <boost/lexical_cast.hpp>
00035
00036 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/common/ResourceBundle.cpp#14 $");
00037
00038 using namespace std;
00039 using namespace boost;
00040
00041 static string globalResourceLocation("");
00042
00043 RecursiveMutex ResourceBundle::mutex;
00044
00045 RecursiveMutex &ResourceBundle::getMutex()
00046 {
00047 return mutex;
00048 }
00049
00050 void ResourceBundle::setGlobalResourceFileLocation(const string &location)
00051 {
00052 globalResourceLocation = location;
00053 }
00054
00055 ResourceBundle::ResourceBundle(
00056 const string &baseName,
00057 const Locale &locale,
00058 const string &location)
00059 : _baseName(baseName),
00060 _locale(locale),
00061 _location(location),
00062 _parent(NULL)
00063 {
00064 loadMessages();
00065 }
00066
00067 ResourceBundle::~ResourceBundle()
00068 {
00069 }
00070
00071 void ResourceBundle::setParent(ResourceBundle *bundle)
00072 {
00073 _parent = bundle;
00074 }
00075
00076 const set<string> ResourceBundle::getKeys() const
00077 {
00078 set<string> keys;
00079
00080 map<string, string>::const_iterator iter = _messages.begin(),
00081 end = _messages.end();
00082
00083 while (iter != end) {
00084 keys.insert((*iter).first);
00085 iter++;
00086 }
00087
00088 if (_parent) {
00089 set<string> parentKeys = _parent->getKeys();
00090
00091 keys.insert(parentKeys.begin(), parentKeys.end());
00092 }
00093
00094 return keys;
00095 }
00096
00097 static string MISSING_KEY("[[unknown key]]");
00098
00099 const string &ResourceBundle::getMessage(const string &key) const
00100 {
00101 map<string, string>::const_iterator iter;
00102 iter = _messages.find(key);
00103 if (iter == _messages.end()) {
00104 if (_parent) {
00105 return _parent->getMessage(key);
00106 }
00107
00108 return MISSING_KEY;
00109 }
00110
00111 return (*iter).second;
00112 }
00113
00114
00115 bool ResourceBundle::hasMessage(const string &key) const
00116 {
00117 return
00118 _messages.find(key) != _messages.end()
00119 || (_parent && _parent->hasMessage(key));
00120 }
00121
00122 const Locale &ResourceBundle::getLocale() const
00123 {
00124 return _locale;
00125 }
00126
00127
00128 const string &ResourceBundle::getBaseName() const
00129 {
00130 return _baseName;
00131 }
00132
00133
00134 static const char APOS = '\'';
00135 static const char LEFT_BRACE = '{';
00136 static const char RIGHT_BRACE = '}';
00137 static const char COMMA = ',';
00138
00139 static string convertPropertyToBoost(string &message)
00140 {
00141 stringstream ss;
00142
00143 bool quoted = false;
00144 char ch;
00145 char nextCh;
00146
00147 for (int i = 0, n = message.length(); i < n; i++) {
00148 ch = message[i];
00149 nextCh = (i + 1 < n) ? message[i + 1] : 0;
00150
00151 if (ch == APOS) {
00152 if (nextCh != APOS) {
00153
00154 quoted = !quoted;
00155 continue;
00156 }
00157
00158
00159
00160 ss << APOS;
00161 i++;
00162 continue;
00163 }
00164
00165 if (quoted || ch != LEFT_BRACE) {
00166 ss << ch;
00167 continue;
00168 }
00169
00170
00171 string::size_type commaPos = message.find(COMMA, i);
00172 string::size_type bracketPos = message.find(RIGHT_BRACE, i);
00173 if (bracketPos == string::npos) {
00174
00175 return message;
00176 }
00177
00178 int argEndIndex = (commaPos == string::npos
00179 ? bracketPos
00180 : min(commaPos, bracketPos));
00181
00182 int argIndex = boost::lexical_cast<int>(
00183 message.substr(i + 1, argEndIndex - (i + 1)));
00184
00185
00186 ss << '%' << (argIndex + 1) << '%';
00187
00188
00189 bool quotedPattern = false;
00190 int bracketDepth = 0;
00191 i = argEndIndex;
00192
00193 bool done = false;
00194 while (!done && i < n) {
00195 ch = message[i];
00196
00197 switch (ch) {
00198 default:
00199 i++;
00200 break;
00201
00202 case APOS:
00203 quotedPattern = !quotedPattern;
00204 i++;
00205 break;
00206
00207 case LEFT_BRACE:
00208 if (!quotedPattern) {
00209 bracketDepth++;
00210 }
00211 i++;
00212 break;
00213
00214 case RIGHT_BRACE:
00215 if (!quotedPattern) {
00216 if (bracketDepth > 0) {
00217 bracketDepth--;
00218 } else {
00219
00220 done = true;
00221 break;
00222 }
00223 }
00224 i++;
00225 break;
00226 }
00227 }
00228
00229 if (i == n) {
00230
00231 return message;
00232 }
00233 }
00234
00235 return ss.str();
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245 void ResourceBundle::loadMessages()
00246 {
00247 fstream in;
00248
00249
00250 string fileName;
00251
00252 if (_locale == Locale("")) {
00253 fileName.assign(_baseName
00254 + ".properties");
00255 } else {
00256 fileName.assign(_baseName
00257 + "_"
00258 + _locale.getDisplayName()
00259 + ".properties");
00260 }
00261
00262
00263 bool tryGlobalLocation = true;
00264 if (!_location.empty()) {
00265 string path = _location + "/" + fileName;
00266 in.open(path.c_str(), ios::in);
00267 if (in.good()) {
00268 tryGlobalLocation = false;
00269 }
00270 }
00271
00272
00273 if (tryGlobalLocation) {
00274 bool tryEnvVar = true;
00275
00276
00277
00278 if (!globalResourceLocation.empty()) {
00279 string path = globalResourceLocation + "/" + fileName;
00280 in.open(path.c_str(), ios::in);
00281 if (in.good()) {
00282 tryEnvVar = false;
00283 }
00284 }
00285
00286 if (tryEnvVar) {
00287 const char *fennelHome = getenv("FENNEL_HOME");
00288 if (fennelHome == NULL) {
00289 return;
00290 }
00291
00292 string path = string(fennelHome) + "/common/" + fileName;
00293 in.open(path.c_str(), ios::in);
00294 if (!in.good()) {
00295 return;
00296 }
00297 }
00298 }
00299
00300 string line, key, message;
00301 while (in.good()) {
00302 getline(in, line);
00303
00304 if (line.length() == 0 || line[0] == '#') {
00305
00306 continue;
00307 }
00308
00309 string::size_type pos = line.find('=');
00310 if (pos == string::npos) {
00311
00312 continue;
00313 }
00314
00315 key = line.substr(0, pos);
00316 message = line.substr(pos + 1);
00317
00318 _messages[key] = convertPropertyToBoost(message);
00319 }
00320
00321 in.close();
00322 }
00323
00324 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/common/ResourceBundle.cpp#14 $");
00325
00326