1 /** @file scim_simple_config.cpp
2 * implementation of SimpleConfig class.
6 * Smart Common Input Method
8 * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this program; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, MA 02111-1307 USA
26 * $Id: scim_simple_config.cpp,v 1.35 2005/07/06 03:57:04 suzhe Exp $
29 #define Uses_SCIM_CONFIG_BASE
30 #define Uses_SCIM_CONFIG_PATH
31 #define Uses_STL_IOSTREAM
32 #define Uses_STL_FSTREAM
36 #include <sys/types.h>
39 #include "scim_private.h"
41 #include "scim_simple_config.h"
43 #ifndef SCIM_SYSCONFDIR
44 #define SCIM_SYSCONFDIR "/etc"
47 #define scim_module_init simple_LTX_scim_module_init
48 #define scim_module_exit simple_LTX_scim_module_exit
49 #define scim_config_module_init simple_LTX_scim_config_module_init
50 #define scim_config_module_create_config simple_LTX_scim_config_module_create_config
55 void scim_module_init (void)
57 SCIM_DEBUG_CONFIG(1) << "Initializing Simple Config module...\n";
60 void scim_module_exit (void)
62 SCIM_DEBUG_CONFIG(1) << "Exiting Simple Config module...\n";
65 void scim_config_module_init ()
67 SCIM_DEBUG_CONFIG(1) << "Initializing Simple Config module (more)...\n";
70 ConfigPointer scim_config_module_create_config ()
72 SCIM_DEBUG_CONFIG(1) << "Creating a Simple Config instance...\n";
73 return new SimpleConfig ();
79 SimpleConfig::SimpleConfig ()
80 : m_need_reload (false)
82 m_update_timestamp.tv_sec = 0;
83 m_update_timestamp.tv_usec = 0;
88 SimpleConfig::~SimpleConfig ()
94 SimpleConfig::valid () const
96 return ConfigBase::valid();
100 SimpleConfig::get_name () const
107 SimpleConfig::read (const String& key, String *pStr) const
109 if (!valid () || !pStr || key.empty()) return false;
111 KeyValueRepository::const_iterator i = m_new_config.find (key);
112 KeyValueRepository::const_iterator end = m_new_config.end ();
115 i = m_config.find (key);
116 end = m_config.end ();
130 SimpleConfig::read (const String& key, int *pl) const
132 if (!valid () || !pl || key.empty()) return false;
134 KeyValueRepository::const_iterator i = m_new_config.find (key);
135 KeyValueRepository::const_iterator end = m_new_config.end ();
137 if (i == end || !i->second.length ()) {
138 i = m_config.find (key);
139 end = m_config.end ();
142 if (i != end && i->second.length ()) {
143 *pl = strtol (i->second.c_str (), (char**) NULL, 10);
153 SimpleConfig::read (const String& key, double* val) const
155 if (!valid () || !val || key.empty()) return false;
157 KeyValueRepository::const_iterator i = m_new_config.find (key);
158 KeyValueRepository::const_iterator end = m_new_config.end ();
160 if (i == end || !i->second.length ()) {
161 i = m_config.find (key);
162 end = m_config.end ();
165 if (i != end && i->second.length ()) {
166 *val = strtod (i->second.c_str (), (char**) NULL);
176 SimpleConfig::read (const String& key, bool* val) const
178 if (!valid () || !val || key.empty()) return false;
180 KeyValueRepository::const_iterator i = m_new_config.find (key);
181 KeyValueRepository::const_iterator end = m_new_config.end ();
183 if (i == end || !i->second.length ()) {
184 i = m_config.find (key);
185 end = m_config.end ();
188 if (i != end && i->second.length ()) {
189 if (i->second == "true" || i->second == "TRUE" || i->second == "True" ||
193 } else if (i->second == "false" || i->second == "FALSE" || i->second == "False" ||
206 SimpleConfig::read (const String& key, std::vector <String>* val) const
208 if (!valid () || !val || key.empty()) return false;
210 KeyValueRepository::const_iterator i = m_new_config.find (key);
211 KeyValueRepository::const_iterator end = m_new_config.end ();
214 i = m_config.find (key);
215 end = m_config.end ();
221 scim_split_string_list (*val, i->second, ',');
230 SimpleConfig::read (const String& key, std::vector <int>* val) const
232 if (!valid () || !val || key.empty()) return false;
234 KeyValueRepository::const_iterator i = m_new_config.find (key);
235 KeyValueRepository::const_iterator end = m_new_config.end ();
238 i = m_config.find (key);
239 end = m_config.end ();
245 std::vector <String> vec;
246 scim_split_string_list (vec, i->second, ',');
248 for (std::vector <String>::iterator j = vec.begin (); j != vec.end (); ++j) {
249 int result = strtol (j->c_str (), (char**)NULL, 10);
250 val->push_back (result);
258 // write the value (return true on success)
260 SimpleConfig::write (const String& key, const String& value)
262 if (!valid () || key.empty()) return false;
264 m_new_config [key] = value;
266 remove_key_from_erased_list (key);
268 m_need_reload = true;
274 SimpleConfig::write (const String& key, int value)
276 if (!valid () || key.empty()) return false;
280 snprintf (buf, 255, "%d", value);
282 m_new_config [key] = String (buf);
284 remove_key_from_erased_list (key);
286 m_need_reload = true;
292 SimpleConfig::write (const String& key, double value)
294 if (!valid () || key.empty()) return false;
298 snprintf (buf, 255, "%lf", value);
300 m_new_config [key] = String (buf);
302 remove_key_from_erased_list (key);
304 m_need_reload = true;
310 SimpleConfig::write (const String& key, bool value)
312 if (!valid () || key.empty()) return false;
315 m_new_config [key] = String ("true");
317 m_new_config [key] = String ("false");
319 remove_key_from_erased_list (key);
321 m_need_reload = true;
327 SimpleConfig::write (const String& key, const std::vector <String>& value)
329 if (!valid () || key.empty()) return false;
331 m_new_config [key] = scim_combine_string_list (value, ',');
333 remove_key_from_erased_list (key);
335 m_need_reload = true;
341 SimpleConfig::write (const String& key, const std::vector <int>& value)
343 if (!valid () || key.empty()) return false;
345 std::vector <String> vec;
348 for (std::vector <int>::const_iterator i = value.begin (); i != value.end (); ++i) {
349 snprintf (buf, 255, "%d", *i);
350 vec.push_back (String (buf));
353 m_new_config [key] = scim_combine_string_list (vec, ',');
355 remove_key_from_erased_list (key);
357 m_need_reload = true;
362 // permanently writes all changes
364 SimpleConfig::flush()
366 if (!valid ()) return false;
368 // If no config has been modified, then just return.
369 if (!m_new_config.size () && !m_erased_keys.size ())
372 String userconf = get_userconf_filename ();
373 String userconf_dir = get_userconf_dir ();
375 if (access (userconf_dir.c_str (), R_OK | W_OK) != 0) {
376 mkdir (userconf_dir.c_str (), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
377 if (access (userconf_dir.c_str (), R_OK | W_OK) != 0)
381 if (userconf.length ()) {
382 // Reload config to ensure user made modification won't lost.
385 std::ofstream os (userconf.c_str ());
386 if (!os) return false;
388 KeyValueRepository::iterator i;
389 std::vector<String>::iterator j;
391 // Merge new config with old ones.
392 for (i = m_new_config.begin (); i != m_new_config.end (); ++i)
393 m_config [i->first] = i->second;
395 // Remove all erased keys.
396 for (j = m_erased_keys.begin (); j != m_erased_keys.end (); ++j) {
397 if ((i = m_config.find (*j)) != m_config.end ())
401 m_new_config.clear ();
402 m_erased_keys.clear ();
404 gettimeofday (&m_update_timestamp, 0);
407 snprintf (buf, 128, "%lu:%lu", m_update_timestamp.tv_sec, m_update_timestamp.tv_usec);
409 m_config [String (SCIM_CONFIG_UPDATE_TIMESTAMP)] = String (buf);
420 SimpleConfig::erase (const String& key)
422 if (!valid ()) return false;
424 KeyValueRepository::iterator i = m_new_config.find(key);
425 KeyValueRepository::iterator j = m_config.find(key);
428 if (i != m_new_config.end ()) {
429 m_new_config.erase (i);
433 if (j != m_config.end ()) {
438 if (ok && std::find (m_erased_keys.begin (), m_erased_keys.end (), key) == m_erased_keys.end ())
439 m_erased_keys.push_back (key);
441 m_need_reload = true;
447 SimpleConfig::reload ()
449 if (!valid ()) return false;
451 if (load_all_config ()) {
452 m_new_config.clear ();
453 m_erased_keys.clear ();
454 m_need_reload = true;
458 m_need_reload = false;
459 return ConfigBase::reload ();
466 SimpleConfig::get_sysconf_dir ()
468 return String (SCIM_SYSCONFDIR) +
469 String (SCIM_PATH_DELIM_STRING) +
474 SimpleConfig::get_userconf_dir ()
476 return scim_get_user_data_dir ();
480 SimpleConfig::get_sysconf_filename ()
482 return get_sysconf_dir () +
483 String (SCIM_PATH_DELIM_STRING) +
488 SimpleConfig::get_userconf_filename ()
490 return get_userconf_dir () +
491 String (SCIM_PATH_DELIM_STRING) +
496 SimpleConfig::trim_blank (const String &str)
498 String::size_type begin, len;
500 begin = str.find_first_not_of (" \t\n\v");
502 if (begin == String::npos)
505 len = str.find_last_not_of (" \t\n\v") - begin + 1;
507 return str.substr (begin, len);
511 SimpleConfig::get_param_portion (const String &str)
513 String::size_type begin = str.find_first_of (" \t\n\v=");
515 if (begin == String::npos) return str;
517 return str.substr (0, begin);
521 SimpleConfig::get_value_portion (const String &str)
523 String::size_type begin = str.find_first_of ("=");
525 if (begin == String::npos || (begin + 1) == str.length ()) return String ("");
527 return trim_blank (str.substr (begin + 1, String::npos));
531 SimpleConfig::parse_config (std::istream &is, KeyValueRepository &config)
533 char *conf_line = new char [SCIM_MAX_CONFIG_LINE_LENGTH];
536 is.getline(conf_line, SCIM_MAX_CONFIG_LINE_LENGTH);
538 String normalized_line = trim_blank(conf_line);
540 if ((normalized_line.find_first_of("#") > 0) && (normalized_line.length() != 0)) {
541 if (normalized_line.find_first_of("=") == String::npos) {
542 SCIM_DEBUG_CONFIG(2) << " Invalid config line : " << normalized_line << "\n";
546 if (normalized_line[0] == '=') {
547 SCIM_DEBUG_CONFIG(2) << " Invalid config line : " << normalized_line << "\n";
551 String param = get_param_portion(normalized_line);
552 KeyValueRepository::iterator i = config.find(param);
554 if (i != config.end()) {
555 SCIM_DEBUG_CONFIG(2) << " Config entry " << normalized_line << " has been read.\n";
557 String value = get_value_portion (normalized_line);
558 config [param] = value;
559 SCIM_DEBUG_CONFIG(2) << " Config entry " << param << "=" << value << " is successfully read.\n";
569 SimpleConfig::save_config (std::ostream &os)
571 KeyValueRepository::iterator i;
572 for (i = m_config.begin (); i != m_config.end (); ++i) {
573 os << i->first << " = " << i->second << "\n";
578 SimpleConfig::load_all_config ()
580 String sysconf = get_sysconf_filename ();
581 String userconf = get_userconf_filename ();
583 KeyValueRepository config;
585 if (userconf.length ()) {
586 std::ifstream is (userconf.c_str ());
588 SCIM_DEBUG_CONFIG(1) << "Parsing user config file: "
590 parse_config (is, config);
594 if (sysconf.length ()) {
595 std::ifstream is (sysconf.c_str ());
597 SCIM_DEBUG_CONFIG(1) << "Parsing system config file: "
599 parse_config (is, config);
603 if (!m_config.size () || (m_update_timestamp.tv_sec == 0 && m_update_timestamp.tv_usec == 0)) {
604 m_config.swap (config);
605 gettimeofday (&m_update_timestamp, 0);
609 KeyValueRepository::iterator it = config.find (String (SCIM_CONFIG_UPDATE_TIMESTAMP));
611 if (it != config.end ()) {
612 std::vector <String> strs;
613 if (scim_split_string_list (strs, it->second, ':') == 2) {
614 time_t sec = (time_t) strtol (strs [0].c_str (), 0, 10);
615 suseconds_t usec = (suseconds_t) strtol (strs [1].c_str (), 0, 10);
617 // The config file is newer, so load it.
618 if (m_update_timestamp.tv_sec < sec || (m_update_timestamp.tv_sec == sec && m_update_timestamp.tv_usec < usec)) {
619 m_config.swap (config);
620 m_update_timestamp.tv_sec = (time_t) sec;
621 m_update_timestamp.tv_usec = (suseconds_t) usec;
630 SimpleConfig::remove_key_from_erased_list (const String &key)
632 std::vector <String>::iterator it = std::find (m_erased_keys.begin (), m_erased_keys.end (), key);
634 if (it != m_erased_keys.end ())
635 m_erased_keys.erase (it);
641 vi:ts=4:nowrap:ai:expandtab