00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "OptionAgent.h"
00010
00011 #include "Environ.h"
00012
00013 #include "Log.h"
00014 #include "Path.h"
00015 #include "FsPath.h"
00016 #include "ScriptAgent.h"
00017 #include "StringTool.h"
00018 #include "HelpException.h"
00019 #include "LogicException.h"
00020 #include "ScriptException.h"
00021 #include "OptionParams.h"
00022 #include "StringMsg.h"
00023 #include "UnknownMsgException.h"
00024 #include "minmax.h"
00025
00026 #include <string.h>
00027 #include <locale.h>
00028
00029 #ifndef LC_MESSAGES
00030 #define LC_MESSAGES LC_CTYPE
00031 #endif
00032
00033
00034 #ifndef SYSTEM_DATA_DIR
00035 #define SYSTEM_DATA_DIR ""
00036 #endif
00037
00038
00039 #ifndef USER_DATA_DIR
00040 #define USER_DATA_DIR ".fillets-ng"
00041 #endif
00042
00043 const char *OptionAgent::CONFIG_FILE = "script/options.lua";
00044
00045
00046
00047
00048
00049
00050 void
00051 OptionAgent::own_init()
00052 {
00053 m_environ = new Environ();
00054 prepareVersion();
00055 prepareDataPaths();
00056 prepareLang();
00057 }
00058
00059
00060
00061
00062
00063 void
00064 OptionAgent::own_shutdown()
00065 {
00066 delete m_environ;
00067 }
00068
00069
00070
00071
00072 void
00073 OptionAgent::prepareVersion()
00074 {
00075 #ifdef VERSION
00076 setParam("version", VERSION);
00077 #else
00078 setParam("version", "0.0.1");
00079 #endif
00080 #ifdef PACKAGE
00081 setParam("package", PACKAGE);
00082 #else
00083 setParam("package", "A game");
00084 #endif
00085 }
00086
00087
00088
00089
00090
00091 void
00092 OptionAgent::prepareDataPaths()
00093 {
00094 registerWatcher("systemdir");
00095 registerWatcher("userdir");
00096 OptionAgent::agent()->setParam("systemdir", SYSTEM_DATA_DIR);
00097
00098 std::string userdir = "";
00099 const char *home = getenv("HOME");
00100 if (home) {
00101 userdir = FsPath::join(home, USER_DATA_DIR);
00102 OptionAgent::agent()->setParam("userdir", userdir);
00103 }
00104 else {
00105 readUserConfig();
00106 }
00107 }
00108
00109
00110
00111
00112
00113
00114 void
00115 OptionAgent::prepareLang()
00116 {
00117 setlocale(LC_ALL, "");
00118
00119 setlocale(LC_NUMERIC, "C");
00120 if (getParam("lang").empty()) {
00121 char *form = setlocale(LC_MESSAGES, NULL);
00122 int size = min(5, strlen(form));
00123 if (form && size >= 2) {
00124 setParam("lang", std::string(form, size));
00125 }
00126 }
00127 }
00128
00129
00130
00131
00132
00133
00134
00135 void
00136 OptionAgent::parseCmdOpt(int argc, char *argv[], const OptionParams ¶ms)
00137 {
00138 if (argc >= 1) {
00139 setParam("program", argv[0]);
00140 }
00141
00142 for (int i = 1; i < argc; ++i) {
00143 if (argv[i][0] == '-') {
00144 parseDashOpt(argv[i], params);
00145 }
00146 else {
00147 parseParamOpt(argv[i], params);
00148 }
00149 }
00150 }
00151
00152
00153
00154
00155
00156
00157 void
00158 OptionAgent::parseDashOpt(const std::string &arg,
00159 const OptionParams ¶ms)
00160 {
00161 if ("-h" == arg || "--help" == arg) {
00162 throw HelpException(ExInfo(getHelpInfo(params)));
00163 }
00164 else if ("-v" == arg || "--version" == arg) {
00165 throw HelpException(ExInfo(getVersionInfo()));
00166 }
00167 else if ("-c" == arg || "--config" == arg) {
00168 throw HelpException(ExInfo(params.getConfig(m_environ)));
00169 }
00170 else {
00171 throw LogicException(ExInfo("unknown option")
00172 .addInfo("arg", arg)
00173 .addInfo("use",
00174 getParam("program") + " --help"));
00175 }
00176 }
00177
00178 void
00179 OptionAgent::parseParamOpt(const std::string &arg,
00180 const OptionParams &)
00181 {
00182
00183 std::string name;
00184 std::string value;
00185 if (splitOpt(arg, &name, &value)) {
00186 setParam(name, value);
00187 }
00188 else {
00189 throw LogicException(ExInfo("unknown option")
00190 .addInfo("arg", arg)
00191 .addInfo("use",
00192 getParam("program") + " --help"));
00193 }
00194 }
00195
00196
00197
00198
00199
00200 bool
00201 OptionAgent::splitOpt(const std::string &option,
00202 std::string *out_name, std::string *out_value)
00203 {
00204 bool result = false;
00205 std::string::size_type pos = option.find('=');
00206 if (pos != std::string::npos) {
00207 if (pos + 1 < option.size()) {
00208 *out_name = option.substr(0, pos);
00209 *out_value = option.substr(pos + 1, std::string::npos);
00210 result = true;
00211 }
00212 }
00213
00214 return result;
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 void
00226 OptionAgent::setParam(const std::string &name, const std::string &value)
00227 {
00228 m_environ->setParam(name, value);
00229 }
00230
00231
00232
00233
00234 void
00235 OptionAgent::setParam(const std::string &name, long value)
00236 {
00237 m_environ->setParam(name, value);
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 std::string
00249 OptionAgent::getParam(const std::string &name,
00250 const std::string &implicit) const
00251 {
00252 return m_environ->getParam(name, implicit);
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 int
00264 OptionAgent::getAsInt(const std::string &name,
00265 int implicit) const
00266 {
00267 return m_environ->getAsInt(name, implicit);
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 bool
00279 OptionAgent::getAsBool(const std::string &name,
00280 bool implicit) const
00281 {
00282 return m_environ->getAsBool(name, implicit);
00283 }
00284
00285
00286
00287
00288
00289 void
00290 OptionAgent::setPersistent(const std::string &name, const std::string &value)
00291 {
00292
00293 Path config = Path::dataWritePath(CONFIG_FILE);
00294
00295 Environ *swap_env = m_environ;
00296 m_environ = new Environ();
00297
00298 try {
00299 if (config.exists()) {
00300 ScriptAgent::agent()->doFile(config);
00301 }
00302 }
00303 catch (ScriptException &e) {
00304 LOG_WARNING(e.info());
00305 }
00306 setParam(name, value);
00307 m_environ->store(config);
00308
00309 delete m_environ;
00310 m_environ = swap_env;
00311 setParam(name, value);
00312 }
00313
00314 void
00315 OptionAgent::setPersistent(const std::string &name, long value)
00316 {
00317 setPersistent(name, StringTool::toString(value));
00318 }
00319
00320
00321
00322
00323 void
00324 OptionAgent::setDefault(const std::string &name, const std::string &value)
00325 {
00326 m_environ->setParam(name, m_environ->getParam(name, value));
00327 }
00328
00329 void
00330 OptionAgent::setDefault(const std::string &name, int value)
00331 {
00332 m_environ->setParam(name, m_environ->getAsInt(name, value));
00333 }
00334
00335 void
00336 OptionAgent::addWatcher(const std::string &name, BaseMsg *msg)
00337 {
00338 m_environ->addWatcher(name, msg);
00339 }
00340
00341 void
00342 OptionAgent::removeWatchers(const std::string &listenerName)
00343 {
00344 m_environ->removeWatchers(listenerName);
00345 }
00346
00347
00348
00349
00350 std::string
00351 OptionAgent::getHelpInfo(const OptionParams ¶ms) const
00352 {
00353 std::string help = "Usage: "
00354 + getParam("program") + " [options] [name=value ...]\n";
00355 help += " -h, --help Show this help\n";
00356 help += " -v, --version Show version\n";
00357 help += " -c, --config Show config\n";
00358 help += "\n";
00359 help += "Config variables:\n";
00360 help += params.getHelp(m_environ);
00361 return help;
00362 }
00363
00364 std::string
00365 OptionAgent::getVersionInfo() const
00366 {
00367 return getParam("package") + " " + getParam("version");
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 void
00379 OptionAgent::receiveString(const StringMsg *msg)
00380 {
00381 if (msg->equalsName("param_changed")) {
00382 std::string param = msg->getValue();
00383 if ("systemdir" == param) {
00384 readSystemConfig();
00385 }
00386 else if ("userdir" == param) {
00387 readUserConfig();
00388 }
00389 else {
00390 throw UnknownMsgException(msg);
00391 }
00392 }
00393 else {
00394 throw UnknownMsgException(msg);
00395 }
00396 }
00397
00398 void
00399 OptionAgent::readSystemConfig()
00400 {
00401 try {
00402 Path systemConfig = Path::dataSystemPath(CONFIG_FILE);
00403 if (systemConfig.exists()) {
00404 ScriptAgent::agent()->doFile(systemConfig);
00405 }
00406 }
00407 catch (ScriptException &e) {
00408 LOG_WARNING(e.info());
00409 }
00410 }
00411
00412 void
00413 OptionAgent::readUserConfig()
00414 {
00415 try {
00416 Path userConfig = Path::dataUserPath(CONFIG_FILE);
00417 if (userConfig.exists()) {
00418 ScriptAgent::agent()->doFile(userConfig);
00419 }
00420 }
00421 catch (ScriptException &e) {
00422 LOG_WARNING(e.info());
00423 }
00424 }
00425