00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <sstream>
00011 #include <iostream>
00012 #include <algorithm>
00013
00014 #include "colvarmodule.h"
00015 #include "colvarvalue.h"
00016 #include "colvarparse.h"
00017
00018
00019
00020 char const * const colvarparse::white_space = " \t";
00021
00022
00023 namespace {
00024
00025
00026 void set_bool(void *p, bool val)
00027 {
00028 bool *v = reinterpret_cast<bool *>(p);
00029 *v = val;
00030 }
00031
00032 }
00033
00034
00035 colvarparse::colvarparse()
00036 : keyword_delimiters_left("\n"+std::string(white_space)+"}"),
00037 keyword_delimiters_right("\n"+std::string(white_space)+"{")
00038 {
00039 colvarparse::clear();
00040 }
00041
00042
00043 void colvarparse::clear()
00044 {
00045 config_string.clear();
00046 clear_keyword_registry();
00047 }
00048
00049
00050 colvarparse::colvarparse(const std::string& conf)
00051 : keyword_delimiters_left("\n"+std::string(white_space)+"}"),
00052 keyword_delimiters_right("\n"+std::string(white_space)+"{")
00053 {
00054 colvarparse::set_string(conf);
00055 }
00056
00057
00058 void colvarparse::set_string(std::string const &conf)
00059 {
00060 if (! config_string.size()) {
00061 colvarparse::clear();
00062 config_string = conf;
00063 }
00064 }
00065
00066
00067 colvarparse::~colvarparse()
00068 {
00069 colvarparse::clear();
00070 }
00071
00072
00073
00074 bool colvarparse::get_key_string_value(std::string const &conf,
00075 char const *key, std::string &data)
00076 {
00077 bool b_found = false, b_found_any = false;
00078 size_t save_pos = 0, found_count = 0;
00079
00080 do {
00081 std::string data_this = "";
00082 b_found = key_lookup(conf, key, &data_this, &save_pos);
00083 if (b_found) {
00084 if (!b_found_any)
00085 b_found_any = true;
00086 found_count++;
00087 data = data_this;
00088 }
00089 } while (b_found);
00090
00091 if (found_count > 1) {
00092 cvm::error("Error: found more than one instance of \""+
00093 std::string(key)+"\".\n", COLVARS_INPUT_ERROR);
00094 }
00095
00096 return b_found_any;
00097 }
00098
00099 bool colvarparse::get_key_string_multi_value(std::string const &conf,
00100 char const *key, std::vector<std::string>& data)
00101 {
00102 bool b_found = false, b_found_any = false;
00103 size_t save_pos = 0, found_count = 0;
00104
00105 data.clear();
00106
00107 do {
00108 std::string data_this = "";
00109 b_found = key_lookup(conf, key, &data_this, &save_pos);
00110 if (b_found) {
00111 if (!b_found_any)
00112 b_found_any = true;
00113 found_count++;
00114 data.push_back(data_this);
00115 }
00116 } while (b_found);
00117
00118 return b_found_any;
00119 }
00120
00121
00122 template<typename TYPE>
00123 void colvarparse::mark_key_set_user(std::string const &key_str,
00124 TYPE const &value,
00125 Parse_Mode const &parse_mode)
00126 {
00127 key_set_modes[to_lower_cppstr(key_str)] = key_set_user;
00128 if (parse_mode & parse_echo) {
00129 cvm::log("# "+key_str+" = "+cvm::to_str(value)+"\n",
00130 cvm::log_user_params());
00131 }
00132 if (parse_mode & parse_deprecation_warning) {
00133 cvm::log("Warning: keyword "+key_str+
00134 " is deprecated. Check the documentation for the current equivalent.\n");
00135 }
00136 }
00137
00138
00139 template<typename TYPE>
00140 void colvarparse::mark_key_set_default(std::string const &key_str,
00141 TYPE const &def_value,
00142 Parse_Mode const &parse_mode)
00143 {
00144 key_set_modes[to_lower_cppstr(key_str)] = key_set_default;
00145 if (parse_mode & parse_echo_default) {
00146 cvm::log("# "+key_str+" = "+cvm::to_str(def_value)+
00147 " [default]\n", cvm::log_default_params());
00148 }
00149 }
00150
00151
00152 void colvarparse::error_key_required(std::string const &key_str,
00153 Parse_Mode const &parse_mode)
00154 {
00155 if (key_already_set(key_str)) {
00156 return;
00157 }
00158 if (parse_mode & parse_restart) {
00159 cvm::error("Error: keyword \""+key_str+
00160 "\" is missing from the restart.\n", COLVARS_INPUT_ERROR);
00161 } else {
00162 cvm::error("Error: keyword \""+key_str+
00163 "\" is required.\n", COLVARS_INPUT_ERROR);
00164 }
00165 }
00166
00167
00168 template<typename TYPE>
00169 int colvarparse::_get_keyval_scalar_value_(std::string const &key_str,
00170 std::string const &data,
00171 TYPE &value,
00172 TYPE const &def_value)
00173 {
00174 std::istringstream is(data);
00175 size_t value_count = 0;
00176 TYPE x(def_value);
00177
00178 while (is >> x) {
00179 value = x;
00180 value_count++;
00181 }
00182
00183 if (value_count == 0) {
00184 return cvm::error("Error: in parsing \""+
00185 key_str+"\".\n", COLVARS_INPUT_ERROR);
00186 }
00187
00188 if (value_count > 1) {
00189 return cvm::error("Error: multiple values "
00190 "are not allowed for keyword \""+
00191 key_str+"\".\n", COLVARS_INPUT_ERROR);
00192 }
00193
00194 return COLVARS_OK;
00195 }
00196
00197
00198 template<>
00199 int colvarparse::_get_keyval_scalar_value_(std::string const &key_str,
00200 std::string const &data,
00201 bool &value,
00202 bool const & )
00203 {
00204 if ( (data == std::string("on")) ||
00205 (data == std::string("yes")) ||
00206 (data == std::string("true")) ) {
00207 set_bool(reinterpret_cast<void *>(&value), true);
00208 } else if ( (data == std::string("off")) ||
00209 (data == std::string("no")) ||
00210 (data == std::string("false")) ) {
00211 set_bool(reinterpret_cast<void *>(&value), false);
00212 } else {
00213 return cvm::error("Error: boolean values only are allowed "
00214 "for \""+key_str+"\".\n", COLVARS_INPUT_ERROR);
00215 }
00216 return COLVARS_OK;
00217 }
00218
00219
00220 template<typename TYPE>
00221 int colvarparse::_get_keyval_scalar_novalue_(std::string const &key_str,
00222 TYPE & ,
00223 Parse_Mode const & )
00224 {
00225 return cvm::error("Error: improper or missing value "
00226 "for \""+key_str+"\".\n", COLVARS_INPUT_ERROR);
00227 }
00228
00229 template<>
00230 int colvarparse::_get_keyval_scalar_novalue_(std::string const &key_str,
00231 bool &value,
00232 Parse_Mode const &parse_mode)
00233 {
00234 set_bool(reinterpret_cast<void *>(&value), true);
00235 mark_key_set_user<bool>(key_str, value, parse_mode);
00236 return COLVARS_OK;
00237 }
00238
00239
00240 template<typename TYPE>
00241 bool colvarparse::_get_keyval_scalar_(std::string const &conf,
00242 char const *key,
00243 TYPE &value,
00244 TYPE const &def_value,
00245 Parse_Mode const &parse_mode)
00246 {
00247 std::string const key_str(key);
00248
00249 std::string data;
00250 bool const b_found_any = get_key_string_value(conf, key, data);
00251
00252 if (data.size()) {
00253
00254 _get_keyval_scalar_value_<TYPE>(key_str, data, value, def_value);
00255
00256 mark_key_set_user<TYPE>(key_str, value, parse_mode);
00257
00258 } else {
00259
00260 if (b_found_any) {
00261
00262 _get_keyval_scalar_novalue_<TYPE>(key_str, value, parse_mode);
00263
00264 } else {
00265
00266 if (parse_mode & parse_required) {
00267 if (cvm::debug()) {
00268 cvm::log("get_keyval, parse_required = "+cvm::to_str(parse_mode & parse_required)+
00269 "\n");
00270 }
00271 error_key_required(key_str, parse_mode);
00272 return false;
00273 }
00274
00275 if ( (parse_mode & parse_override) || !(key_already_set(key)) ) {
00276 value = def_value;
00277 mark_key_set_default<TYPE>(key_str, value, parse_mode);
00278 }
00279 }
00280 }
00281
00282 return b_found_any;
00283 }
00284
00285
00286 template<typename TYPE>
00287 bool colvarparse::_get_keyval_vector_(std::string const &conf,
00288 char const *key,
00289 std::vector<TYPE> &values,
00290 std::vector<TYPE> const &def_values,
00291 Parse_Mode const &parse_mode)
00292 {
00293 std::string const key_str(key);
00294
00295 std::string data;
00296 bool const b_found_any = get_key_string_value(conf, key, data);
00297
00298 if (data.size()) {
00299 std::istringstream is(data);
00300
00301 if (values.size() == 0) {
00302
00303 std::vector<TYPE> x;
00304 if (def_values.size()) {
00305 x = def_values;
00306 } else {
00307 x.assign(1, TYPE());
00308 }
00309
00310 for (size_t i = 0;
00311 ( is >> x[ ((i<x.size()) ? i : x.size()-1) ] );
00312 i++) {
00313 values.push_back(x[ ((i<x.size()) ? i : x.size()-1) ]);
00314 }
00315
00316 } else {
00317
00318 size_t i = 0;
00319 for ( ; i < values.size(); i++) {
00320 TYPE x(values[i]);
00321 if (is >> x) {
00322 values[i] = x;
00323 } else {
00324 cvm::error("Error: in parsing \""+
00325 key_str+"\".\n", COLVARS_INPUT_ERROR);
00326 }
00327 }
00328 }
00329
00330 mark_key_set_user< std::vector<TYPE> >(key_str, values, parse_mode);
00331
00332 } else {
00333
00334 if (b_found_any) {
00335 cvm::error("Error: improper or missing values for \""+
00336 key_str+"\".\n", COLVARS_INPUT_ERROR);
00337 } else {
00338
00339 if ((values.size() > 0) && (values.size() != def_values.size())) {
00340 cvm::error("Error: the number of default values for \""+
00341 key_str+"\" is different from the number of "
00342 "current values.\n", COLVARS_BUG_ERROR);
00343 }
00344
00345 if (parse_mode & parse_required) {
00346 error_key_required(key_str, parse_mode);
00347 return false;
00348 }
00349
00350 if ( (parse_mode & parse_override) || !(key_already_set(key)) ) {
00351 for (size_t i = 0; i < values.size(); i++) {
00352 values[i] = def_values[i];
00353 }
00354 mark_key_set_default< std::vector<TYPE> >(key_str, def_values,
00355 parse_mode);
00356 }
00357
00358 }
00359 }
00360
00361 return b_found_any;
00362 }
00363
00364
00365
00366
00367
00368 bool colvarparse::get_keyval(std::string const &conf,
00369 char const *key,
00370 int &value,
00371 int const &def_value,
00372 Parse_Mode const parse_mode)
00373 {
00374 return _get_keyval_scalar_<int>(conf, key, value, def_value, parse_mode);
00375 }
00376
00377 bool colvarparse::get_keyval(std::string const &conf,
00378 char const *key,
00379 size_t &value,
00380 size_t const &def_value,
00381 Parse_Mode const parse_mode)
00382 {
00383 return _get_keyval_scalar_<size_t>(conf, key, value, def_value, parse_mode);
00384 }
00385
00386 bool colvarparse::get_keyval(std::string const &conf,
00387 char const *key,
00388 long &value,
00389 long const &def_value,
00390 Parse_Mode const parse_mode)
00391 {
00392 return _get_keyval_scalar_<long>(conf, key, value, def_value, parse_mode);
00393 }
00394
00395 bool colvarparse::get_keyval(std::string const &conf,
00396 char const *key,
00397 cvm::step_number &value,
00398 cvm::step_number const &def_value,
00399 Parse_Mode const parse_mode)
00400 {
00401 return _get_keyval_scalar_<cvm::step_number>(conf, key, value, def_value, parse_mode);
00402 }
00403
00404 bool colvarparse::get_keyval(std::string const &conf,
00405 char const *key,
00406 std::string &value,
00407 std::string const &def_value,
00408 Parse_Mode const parse_mode)
00409 {
00410 return _get_keyval_scalar_<std::string>(conf, key, value, def_value, parse_mode);
00411 }
00412
00413 bool colvarparse::get_keyval(std::string const &conf,
00414 char const *key,
00415 cvm::real &value,
00416 cvm::real const &def_value,
00417 Parse_Mode const parse_mode)
00418 {
00419 return _get_keyval_scalar_<cvm::real>(conf, key, value, def_value, parse_mode);
00420 }
00421
00422 bool colvarparse::get_keyval(std::string const &conf,
00423 char const *key,
00424 cvm::rvector &value,
00425 cvm::rvector const &def_value,
00426 Parse_Mode const parse_mode)
00427 {
00428 return _get_keyval_scalar_<cvm::rvector>(conf, key, value, def_value, parse_mode);
00429 }
00430
00431 bool colvarparse::get_keyval(std::string const &conf,
00432 char const *key,
00433 cvm::quaternion &value,
00434 cvm::quaternion const &def_value,
00435 Parse_Mode const parse_mode)
00436 {
00437 return _get_keyval_scalar_<cvm::quaternion>(conf, key, value, def_value, parse_mode);
00438 }
00439
00440 bool colvarparse::get_keyval(std::string const &conf,
00441 char const *key,
00442 colvarvalue &value,
00443 colvarvalue const &def_value,
00444 Parse_Mode const parse_mode)
00445 {
00446 return _get_keyval_scalar_<colvarvalue>(conf, key, value, def_value, parse_mode);
00447 }
00448
00449 bool colvarparse::get_keyval(std::string const &conf,
00450 char const *key,
00451 bool &value,
00452 bool const &def_value,
00453 Parse_Mode const parse_mode)
00454 {
00455 return _get_keyval_scalar_<bool>(conf, key, value, def_value, parse_mode);
00456 }
00457
00458
00459
00460
00461 bool colvarparse::get_keyval(std::string const &conf,
00462 char const *key,
00463 std::vector<int> &values,
00464 std::vector<int> const &def_values,
00465 Parse_Mode const parse_mode)
00466 {
00467 return _get_keyval_vector_<int>(conf, key, values, def_values, parse_mode);
00468 }
00469
00470 bool colvarparse::get_keyval(std::string const &conf,
00471 char const *key,
00472 std::vector<size_t> &values,
00473 std::vector<size_t> const &def_values,
00474 Parse_Mode const parse_mode)
00475 {
00476 return _get_keyval_vector_<size_t>(conf, key, values, def_values, parse_mode);
00477 }
00478
00479 bool colvarparse::get_keyval(std::string const &conf,
00480 char const *key,
00481 std::vector<long> &values,
00482 std::vector<long> const &def_values,
00483 Parse_Mode const parse_mode)
00484 {
00485 return _get_keyval_vector_<long>(conf, key, values, def_values, parse_mode);
00486 }
00487
00488 bool colvarparse::get_keyval(std::string const &conf,
00489 char const *key,
00490 std::vector<std::string> &values,
00491 std::vector<std::string> const &def_values,
00492 Parse_Mode const parse_mode)
00493 {
00494 return _get_keyval_vector_<std::string>(conf, key, values, def_values, parse_mode);
00495 }
00496
00497 bool colvarparse::get_keyval(std::string const &conf,
00498 char const *key,
00499 std::vector<cvm::real> &values,
00500 std::vector<cvm::real> const &def_values,
00501 Parse_Mode const parse_mode)
00502 {
00503 return _get_keyval_vector_<cvm::real>(conf, key, values, def_values, parse_mode);
00504 }
00505
00506 bool colvarparse::get_keyval(std::string const &conf,
00507 char const *key,
00508 std::vector<cvm::rvector> &values,
00509 std::vector<cvm::rvector> const &def_values,
00510 Parse_Mode const parse_mode)
00511 {
00512 return _get_keyval_vector_<cvm::rvector>(conf, key, values, def_values, parse_mode);
00513 }
00514
00515 bool colvarparse::get_keyval(std::string const &conf,
00516 char const *key,
00517 std::vector<cvm::quaternion> &values,
00518 std::vector<cvm::quaternion> const &def_values,
00519 Parse_Mode const parse_mode)
00520 {
00521 return _get_keyval_vector_<cvm::quaternion>(conf, key, values, def_values, parse_mode);
00522 }
00523
00524 bool colvarparse::get_keyval(std::string const &conf,
00525 char const *key,
00526 std::vector<colvarvalue> &values,
00527 std::vector<colvarvalue> const &def_values,
00528 Parse_Mode const parse_mode)
00529 {
00530 return _get_keyval_vector_<colvarvalue>(conf, key, values, def_values, parse_mode);
00531 }
00532
00533
00534 void colvarparse::add_keyword(char const *key)
00535 {
00536 std::string const key_str_lower(to_lower_cppstr(std::string(key)));
00537
00538 if (key_set_modes.find(key_str_lower) != key_set_modes.end()) {
00539 return;
00540 }
00541
00542 key_set_modes[key_str_lower] = key_not_set;
00543
00544 allowed_keywords.push_back(key_str_lower);
00545 }
00546
00547
00548 bool colvarparse::key_already_set(std::string const &key_str)
00549 {
00550 std::string const key_str_lower(to_lower_cppstr(key_str));
00551
00552 if (key_set_modes.find(key_str_lower) == key_set_modes.end()) {
00553 return false;
00554 }
00555
00556 return (key_set_modes[key_str_lower] > 0);
00557 }
00558
00559
00560 void colvarparse::strip_values(std::string &conf)
00561 {
00562 size_t offset = 0;
00563 data_begin_pos.sort();
00564 data_end_pos.sort();
00565 std::list<size_t>::iterator data_begin_pos_last = std::unique(data_begin_pos.begin(), data_begin_pos.end());
00566 data_begin_pos.erase(data_begin_pos_last, data_begin_pos.end());
00567 std::list<size_t>::iterator data_end_pos_last = std::unique(data_end_pos.begin(), data_end_pos.end());
00568 data_end_pos.erase(data_end_pos_last, data_end_pos.end());
00569
00570 std::list<size_t>::iterator data_begin = data_begin_pos.begin();
00571 std::list<size_t>::iterator data_end = data_end_pos.begin();
00572
00573 for ( ; (data_begin != data_begin_pos.end()) &&
00574 (data_end != data_end_pos.end()) ;
00575 data_begin++, data_end++) {
00576 size_t const nchars = *data_end-*data_begin;
00577 conf.erase(*data_begin - offset, nchars);
00578 offset += nchars;
00579 }
00580 }
00581
00582
00583 void colvarparse::clear_keyword_registry()
00584 {
00585 key_set_modes.clear();
00586 allowed_keywords.clear();
00587 data_begin_pos.clear();
00588 data_end_pos.clear();
00589 }
00590
00591
00592 int colvarparse::check_keywords(std::string &conf, char const *key)
00593 {
00594 if (cvm::debug())
00595 cvm::log("Configuration string for \""+std::string(key)+
00596 "\": \"\n"+conf+"\".\n");
00597
00598 strip_values(conf);
00599
00600
00601
00602 std::string line;
00603 std::istringstream is(conf);
00604 while (cvm::getline(is, line)) {
00605 if (line.size() == 0)
00606 continue;
00607 if (line.find_first_not_of(white_space) ==
00608 std::string::npos)
00609 continue;
00610
00611 std::string uk;
00612 std::istringstream line_is(line);
00613 line_is >> uk;
00614
00615
00616 uk = to_lower_cppstr(uk);
00617
00618 bool found_keyword = false;
00619 for (std::list<std::string>::iterator ki = allowed_keywords.begin();
00620 ki != allowed_keywords.end(); ki++) {
00621 if (uk == *ki) {
00622 found_keyword = true;
00623 break;
00624 }
00625 }
00626 if (!found_keyword) {
00627 cvm::error("Error: keyword \""+uk+"\" is not supported, "
00628 "or not recognized in this context.\n", COLVARS_INPUT_ERROR);
00629 return COLVARS_INPUT_ERROR;
00630 }
00631 }
00632
00633 clear_keyword_registry();
00634
00635 return COLVARS_OK;
00636 }
00637
00638
00639 std::istream & colvarparse::read_config_line(std::istream &is,
00640 std::string &line)
00641 {
00642 cvm::getline(is, line);
00643 config_string += line+'\n';
00644 size_t const comment = line.find('#');
00645 if (comment != std::string::npos) {
00646 line.erase(comment);
00647 }
00648 return is;
00649 }
00650
00651
00652 std::istream & colvarparse::getline_nocomments(std::istream &is,
00653 std::string &line)
00654 {
00655 cvm::getline(is, line);
00656 size_t const comment = line.find('#');
00657 if (comment != std::string::npos) {
00658 line.erase(comment);
00659 }
00660 return is;
00661 }
00662
00663
00664 bool colvarparse::key_lookup(std::string const &conf,
00665 char const *key_in,
00666 std::string *data,
00667 size_t *save_pos)
00668 {
00669 if (cvm::debug()) {
00670 cvm::log("Looking for the keyword \""+std::string(key_in)+
00671 "\" and its value.\n");
00672 }
00673
00674
00675 add_keyword(key_in);
00676
00677
00678 std::string const key(to_lower_cppstr(key_in));
00679
00680
00681
00682 std::string const conf_lower(to_lower_cppstr(conf));
00683
00684
00685 if (data != NULL) {
00686 data->clear();
00687 }
00688
00689
00690 size_t pos = conf_lower.find(key, (save_pos != NULL) ? *save_pos : 0);
00691
00692
00693 while (true) {
00694
00695 if (pos == std::string::npos) {
00696
00697 if (cvm::debug()) {
00698 cvm::log("Keyword \""+std::string(key_in)+"\" not found.\n");
00699 }
00700 return false;
00701 }
00702
00703 bool b_isolated_left = true, b_isolated_right = true;
00704
00705 if (pos > 0) {
00706 if (keyword_delimiters_left.find(conf[pos-1]) == std::string::npos) {
00707
00708 b_isolated_left = false;
00709 } else {
00710 size_t const pl = conf_lower.rfind("\n", pos);
00711 size_t const line_begin = (pl == std::string::npos) ? 0 : pl+1;
00712 size_t const pchar =
00713 conf_lower.find_first_not_of(keyword_delimiters_left, line_begin);
00714 size_t const first_text = (pchar == std::string::npos) ? pos : pchar;
00715 if (first_text < pos) {
00716
00717
00718 b_isolated_left = false;
00719 }
00720 }
00721 }
00722
00723 if (pos < conf.size()-key.size()-1) {
00724 if (keyword_delimiters_right.find(conf[pos+key.size()]) ==
00725 std::string::npos) {
00726
00727 b_isolated_right = false;
00728 }
00729 }
00730
00731
00732 bool const b_not_within_block = (check_braces(conf, pos) == COLVARS_OK);
00733
00734 bool const b_isolated = (b_isolated_left && b_isolated_right &&
00735 b_not_within_block);
00736
00737 if (b_isolated) {
00738
00739 break;
00740 } else {
00741
00742 pos = conf_lower.find(key, pos+key.size());
00743 }
00744 }
00745
00746 if (save_pos != NULL) {
00747
00748
00749 *save_pos = pos + key.size();
00750 }
00751
00752
00753 size_t pl = conf.rfind("\n", pos);
00754 size_t line_begin = (pl == std::string::npos) ? 0 : pl+1;
00755 size_t nl = conf.find("\n", pos);
00756 size_t line_end = (nl == std::string::npos) ? conf.size() : nl;
00757 std::string line(conf, line_begin, (line_end-line_begin));
00758
00759 size_t data_begin = (to_lower_cppstr(line)).find(key) + key.size();
00760 data_begin = line.find_first_not_of(white_space, data_begin+1);
00761
00762 if (data_begin != std::string::npos) {
00763
00764 size_t data_end = line.find_last_not_of(white_space) + 1;
00765 data_end = (data_end == std::string::npos) ? line.size() : data_end;
00766
00767 size_t brace = line.find('{', data_begin);
00768 size_t brace_last = brace;
00769
00770 if (brace != std::string::npos) {
00771
00772
00773
00774
00775
00776
00777
00778 int brace_count = 1;
00779
00780 while (brace_count > 0) {
00781
00782 brace = line.find_first_of("{}", brace_last+1);
00783
00784 while (brace < std::string::npos) {
00785 brace_last = brace;
00786 if (line[brace] == '{') brace_count++;
00787 if (line[brace] == '}') brace_count--;
00788 if (brace_count == 0) {
00789 data_end = brace+1;
00790 break;
00791 }
00792 brace = line.find_first_of("{}", brace+1);
00793 }
00794
00795 if (brace_count == 0) {
00796 data_end = brace+1;
00797 break;
00798 }
00799
00800 if (brace == std::string::npos) {
00801
00802
00803 if (line_end >= conf.size()) {
00804 cvm::error("Parse error: reached the end while "
00805 "looking for closing brace; until now "
00806 "the following was parsed: \"\n"+
00807 line+"\".\n", COLVARS_INPUT_ERROR);
00808 return false;
00809 }
00810
00811 line_begin = line_end;
00812 nl = conf.find('\n', line_begin+1);
00813 if (nl == std::string::npos)
00814 line_end = conf.size();
00815 else
00816 line_end = nl;
00817 line.append(conf, line_begin, (line_end-line_begin));
00818
00819
00820
00821
00822 }
00823
00824 if (brace_count < 0) {
00825 cvm::error("Error: found closing brace without opening brace.\n", COLVARS_INPUT_ERROR);
00826 }
00827 }
00828
00829
00830 data_begin = line.find_first_of('{') + 1;
00831 data_begin = line.find_first_not_of(white_space,
00832 data_begin);
00833
00834 data_end = line.find_last_of('}', line.size()) - 1;
00835 data_end = line.find_last_not_of(white_space,
00836 data_end) + 1;
00837 }
00838
00839 if (data != NULL) {
00840 data->append(line, data_begin, (data_end-data_begin));
00841
00842 if (cvm::debug()) {
00843 cvm::log("Keyword value = \""+*data+"\".\n");
00844 }
00845
00846 if (data->size()) {
00847 data_begin_pos.push_back(conf.find(*data, pos+key.size()));
00848 data_end_pos.push_back(data_begin_pos.back()+data->size());
00849 }
00850 }
00851 }
00852
00853 if (save_pos != NULL) *save_pos = line_end;
00854
00855 return true;
00856 }
00857
00858
00859 colvarparse::read_block::read_block(std::string const &key_in,
00860 std::string *data_in)
00861 : key(key_in), data(data_in)
00862 {
00863 }
00864
00865
00866 colvarparse::read_block::~read_block()
00867 {}
00868
00869
00870 std::istream & operator>> (std::istream &is, colvarparse::read_block const &rb)
00871 {
00872 std::streampos start_pos = is.tellg();
00873 std::string read_key, next;
00874
00875 if ( !(is >> read_key) || !(read_key == rb.key) ||
00876 !(is >> next) ) {
00877
00878
00879 is.clear();
00880 is.seekg(start_pos, std::ios::beg);
00881 is.setstate(std::ios::failbit);
00882 return is;
00883 }
00884
00885 if (next != "{") {
00886 if (rb.data) {
00887 *(rb.data) = next;
00888 }
00889 return is;
00890 }
00891
00892 size_t brace_count = 1;
00893 std::string line;
00894 while (colvarparse::getline_nocomments(is, line)) {
00895 size_t br = 0, br_old = 0;
00896 while ( (br = line.find_first_of("{}", br)) != std::string::npos) {
00897 if (line[br] == '{') brace_count++;
00898 if (line[br] == '}') brace_count--;
00899 br_old = br;
00900 br++;
00901 }
00902 if (brace_count) {
00903 if (rb.data) {
00904 (rb.data)->append(line + "\n");
00905 }
00906 }
00907 else {
00908 if (rb.data) {
00909 (rb.data)->append(line, 0, br_old);
00910 }
00911 break;
00912 }
00913 }
00914 if (brace_count) {
00915
00916
00917 is.clear();
00918 is.seekg(start_pos, std::ios::beg);
00919 is.setstate(std::ios::failbit);
00920 }
00921 return is;
00922 }
00923
00924
00925 int colvarparse::check_braces(std::string const &conf,
00926 size_t const start_pos)
00927 {
00928 int brace_count = 0;
00929 size_t brace = start_pos;
00930 while ((brace = conf.find_first_of("{}", brace)) != std::string::npos) {
00931 if (conf[brace] == '{') brace_count++;
00932 if (conf[brace] == '}') brace_count--;
00933 brace++;
00934 }
00935 return (brace_count != 0) ? COLVARS_INPUT_ERROR : COLVARS_OK;
00936 }
00937
00938
00939 int colvarparse::check_ascii(std::string const &conf)
00940 {
00941
00942 std::string line;
00943 std::istringstream is(conf);
00944 while (cvm::getline(is, line)) {
00945 unsigned char const * const uchars =
00946 reinterpret_cast<unsigned char const *>(line.c_str());
00947 for (size_t i = 0; i < line.size(); i++) {
00948 if (uchars[i] & 0x80U) {
00949 cvm::log("Warning: non-ASCII character detected in this line: \""+
00950 line+"\".\n");
00951 }
00952 }
00953 }
00954 return COLVARS_OK;
00955 }
00956
00957
00958 void colvarparse::split_string(const std::string& data, const std::string& delim, std::vector<std::string>& dest) {
00959 size_t index = 0, new_index = 0;
00960 std::string tmpstr;
00961 while (index != data.length()) {
00962 new_index = data.find(delim, index);
00963 if (new_index != std::string::npos) tmpstr = data.substr(index, new_index - index);
00964 else tmpstr = data.substr(index, data.length());
00965 if (!tmpstr.empty()) {
00966 dest.push_back(tmpstr);
00967 }
00968 if (new_index == std::string::npos) break;
00969 index = new_index + 1;
00970 }
00971 }