Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

colvarparse.C

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 
00003 // This file is part of the Collective Variables module (Colvars).
00004 // The original version of Colvars and its updates are located at:
00005 // https://github.com/Colvars/colvars
00006 // Please update all Colvars source files before making any changes.
00007 // If you wish to distribute your changes, please submit them to the
00008 // Colvars repository at GitHub.
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 // space & tab
00020 char const * const colvarparse::white_space = " \t";
00021 
00022 
00023 namespace {
00024 
00025   // Avoid having to put the bool assignment in the template :-(
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 & /* def_value */)
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 & /* value */,
00223                                              Parse_Mode const & /* parse_mode */)
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 { // No string value
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 // single-value keyword parsers
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 // multiple-value keyword parsers
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   // after stripping, the config string has either empty lines, or
00600   // lines beginning with a keyword
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     // if (cvm::debug())
00615     //   cvm::log ("Checking the validity of \""+uk+"\" from line:\n" + line);
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   // add this keyword to the register (in its camelCase version)
00675   add_keyword(key_in);
00676 
00677   // use the lowercase version from now on
00678   std::string const key(to_lower_cppstr(key_in));
00679 
00680   // "conf_lower" is only used to lookup the keyword, but its value
00681   // will be read from "conf", in order not to mess up file names
00682   std::string const conf_lower(to_lower_cppstr(conf));
00683 
00684   // by default, there is no value, unless we found one
00685   if (data != NULL) {
00686     data->clear();
00687   }
00688 
00689   // start from the first occurrence of key
00690   size_t pos = conf_lower.find(key, (save_pos != NULL) ? *save_pos : 0);
00691 
00692   // iterate over all instances of the substring until it finds it as isolated keyword
00693   while (true) {
00694 
00695     if (pos == std::string::npos) {
00696       // no valid instance of the keyword has been found
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         // none of the valid delimiting characters is on the left of key
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           // There are some non-delimiting characters to the left of the
00717           // keyword on the same line
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         // none of the valid delimiting characters is on the right of key
00727         b_isolated_right = false;
00728       }
00729     }
00730 
00731     // check that there are matching braces between here and the end of conf
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       // found it
00739       break;
00740     } else {
00741       // try the next occurrence of key
00742       pos = conf_lower.find(key, pos+key.size());
00743     }
00744   }
00745 
00746   if (save_pos != NULL) {
00747   // save the pointer for a future call (when iterating over multiple
00748   // valid instances of the same keyword)
00749     *save_pos = pos + key.size();
00750   }
00751 
00752   // get the remainder of the line
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);  // look for an opening brace
00768     size_t brace_last = brace;
00769 
00770     if (brace != std::string::npos) {
00771 
00772       // find the matching closing brace
00773 
00774 //       if (cvm::debug()) {
00775 //         cvm::log("Multi-line value, config is now \""+line+"\".\n");
00776 //       }
00777 
00778       int brace_count = 1;
00779 
00780       while (brace_count > 0) {
00781 
00782         brace = line.find_first_of("{}", brace_last+1);
00783         // find all braces within this line
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           // add a new line
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 //           if (cvm::debug()) {
00820 //             cvm::log("Added a new line, config is now \""+line+"\".\n");
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       // strip the leading and trailing braces
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     // the requested keyword has not been found, or it is not possible
00878     // to read data after it
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     // end-of-file reached
00916     // restore initial position
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   // Check for non-ASCII characters
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 }

Generated on Tue Apr 23 04:22:50 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002