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

colvarscript.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 <cstdlib>
00011 #include <cstring>
00012 #include <sstream>
00013 
00014 #include "colvarproxy.h"
00015 #include "colvardeps.h"
00016 #include "colvarscript.h"
00017 #include "colvarscript_commands.h"
00018 
00019 
00020 
00021 #ifdef COLVARS_TCL
00028 extern "C" int tcl_run_colvarscript_command(ClientData clientData,
00029                                             Tcl_Interp *interp_in,
00030                                             int objc, Tcl_Obj *const objv[]);
00031 #endif
00032 
00033 
00034 colvarscript::colvarscript(colvarproxy *p, colvarmodule *m)
00035  : proxy_(p),
00036    colvars(m)
00037 {
00038   cmd_names = NULL;
00039   init_commands();
00040 #ifdef COLVARS_TCL
00041   // must be called after constructing derived proxy class to allow for overloading
00042   proxy()->init_tcl_pointers();
00043   // TODO put this in backend functions so we don't have to delete
00044   Tcl_Interp *const interp = proxy()->get_tcl_interp();
00045   if (interp == NULL) {
00046     cvm::error("Error: trying to construct colvarscript without a Tcl interpreter.\n");
00047     return;
00048   }
00049   Tcl_DeleteCommand(interp, "cv");
00050   Tcl_CreateObjCommand(interp, "cv", tcl_run_colvarscript_command,
00051                        (ClientData) this, (Tcl_CmdDeleteProc *) NULL);
00052   cvm::log("Redefining the Tcl \"cv\" command to the new script interface.\n");
00053 #endif
00054 }
00055 
00056 
00057 colvarscript::~colvarscript()
00058 {
00059   if (cmd_names) {
00060     delete [] cmd_names;
00061     cmd_names = NULL;
00062   }
00063 }
00064 
00065 
00066 int colvarscript::init_commands()
00067 {
00068   if (cvm::debug()) {
00069     cvm::log("Called colvarcript::init_commands()\n");
00070   }
00071 
00072   cmd_help.resize(colvarscript::cv_n_commands);
00073   cmd_rethelp.resize(colvarscript::cv_n_commands);
00074   cmd_n_args_min.resize(colvarscript::cv_n_commands);
00075   cmd_n_args_max.resize(colvarscript::cv_n_commands);
00076   cmd_arghelp.resize(colvarscript::cv_n_commands);
00077   cmd_full_help.resize(colvarscript::cv_n_commands);
00078   cmd_fns.resize(colvarscript::cv_n_commands);
00079 
00080   if (cmd_names) {
00081     delete [] cmd_names;
00082     cmd_names = NULL;
00083   }
00084   cmd_names = new char const * [colvarscript::cv_n_commands];
00085 
00086 #undef COLVARSCRIPT_COMMANDS_H // disable include guard
00087 #if defined(CVSCRIPT)
00088 #undef CVSCRIPT // disable default macro
00089 #endif
00090 #define CVSCRIPT_COMM_INIT(COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGHELP) {   \
00091     init_command(COMM,#COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGHELP,&(CVSCRIPT_COMM_FNAME(COMM))); \
00092   }
00093 #define CVSCRIPT(COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGS,FN_BODY)  \
00094   CVSCRIPT_COMM_INIT(COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGS)
00095 
00096 #include "colvarscript_commands.h"
00097 
00098 #undef CVSCRIPT_COMM_INIT
00099 #undef CVSCRIPT
00100 
00101   return COLVARS_OK;
00102 }
00103 
00104 
00105 int colvarscript::init_command(colvarscript::command const &comm,
00106                                char const *name, char const *help,
00107                                int n_args_min, int n_args_max,
00108                                char const *arghelp,
00109                                int (*fn)(void *, int, unsigned char * const *))
00110 {
00111   cmd_str_map[std::string(name)] = comm;
00112   cmd_names[comm] = name;
00113 
00114   // Initialize short help string and return-value help string (if present)
00115   {
00116     std::string const help_str(help);
00117     std::istringstream is(help_str);
00118     std::string line;
00119     std::getline(is, line);
00120     cmd_help[comm] = line;
00121     cmd_rethelp[comm] = "";
00122     while (std::getline(is, line)) {
00123       cmd_rethelp[comm] += line + "\n";
00124     }
00125   }
00126 
00127   // Initialize arguments' help strings
00128   cmd_n_args_min[comm] = n_args_min;
00129   cmd_n_args_max[comm] = n_args_max;
00130   {
00131     std::string const arghelp_str(arghelp);
00132     std::istringstream is(arghelp_str);
00133     std::string line;
00134     for (int iarg = 0; iarg < n_args_max; iarg++) {
00135       if (! std::getline(is, line)) {
00136         return cvm::error("Error: could not initialize help string for scripting "
00137                           "command \""+std::string(name)+"\".\n", COLVARS_BUG_ERROR);
00138       }
00139       cmd_arghelp[comm].push_back(line);
00140     }
00141   }
00142 
00143   cmd_full_help[comm] = cmd_help[comm]+"\n";
00144   if (cmd_n_args_min[comm] > 0) {
00145     cmd_full_help[comm] += "\nParameters\n";
00146     cmd_full_help[comm] += "----------\n\n";
00147     size_t i;
00148     for (i = 0; i < cmd_n_args_min[comm]; i++) {
00149       cmd_full_help[comm] += cmd_arghelp[comm][i]+"\n";
00150     }
00151     for (i = cmd_n_args_min[comm]; i < cmd_n_args_max[comm]; i++) {
00152       cmd_full_help[comm] += cmd_arghelp[comm][i]+" (optional)\n";
00153     }
00154   }
00155   if (cmd_rethelp[comm].size() > 0) {
00156     cmd_full_help[comm] += "\nReturns\n";
00157     cmd_full_help[comm] += "-------\n\n";
00158     cmd_full_help[comm] += cmd_rethelp[comm]+"\n";
00159   }
00160 
00161   cmd_fns[comm] = fn;
00162   if (cvm::debug()) {
00163     cvm::log("Defined command \""+std::string(name)+"\", with help string:\n");
00164     cvm::log(get_command_full_help(name));
00165   }
00166 
00167   return COLVARS_OK;
00168 }
00169 
00170 
00171 std::string colvarscript::get_cmd_prefix(colvarscript::Object_type t)
00172 {
00173   switch (t) {
00174   case use_module:
00175     return std::string("cv_"); break;
00176   case use_colvar:
00177     return std::string("colvar_"); break;
00178   case use_bias:
00179     return std::string("bias_"); break;
00180   default:
00181     cvm::error("Error: undefined colvarscript object type.", COLVARS_BUG_ERROR);
00182     return std::string("");
00183   }
00184 }
00185 
00186 
00187 
00188 char const *colvarscript::get_command_help(char const *cmd)
00189 {
00190   if (cmd_str_map.count(cmd) > 0) {
00191     colvarscript::command const c = cmd_str_map[std::string(cmd)];
00192     return cmd_help[c].c_str();
00193   }
00194   cvm::error("Error: command "+std::string(cmd)+
00195              " is not implemented.\n", COLVARS_INPUT_ERROR);
00196   return NULL;
00197 }
00198 
00199 
00200 char const *colvarscript::get_command_rethelp(char const *cmd)
00201 {
00202   if (cmd_str_map.count(cmd) > 0) {
00203     colvarscript::command const c = cmd_str_map[std::string(cmd)];
00204     return cmd_rethelp[c].c_str();
00205   }
00206   cvm::error("Error: command "+std::string(cmd)+
00207              " is not implemented.\n", COLVARS_INPUT_ERROR);
00208   return NULL;
00209 }
00210 
00211 
00212 char const *colvarscript::get_command_arghelp(char const *cmd, int i)
00213 {
00214   if (cmd_str_map.count(cmd) > 0) {
00215     colvarscript::command const c = cmd_str_map[std::string(cmd)];
00216     return cmd_arghelp[c][i].c_str();
00217   }
00218   cvm::error("Error: command "+std::string(cmd)+
00219              " is not implemented.\n", COLVARS_INPUT_ERROR);
00220   return NULL;
00221 }
00222 
00223 
00224 int colvarscript::get_command_n_args_min(char const *cmd)
00225 {
00226   if (cmd_str_map.count(cmd) > 0) {
00227     colvarscript::command const c = cmd_str_map[std::string(cmd)];
00228     return cmd_n_args_min[c];
00229   }
00230   cvm::error("Error: command "+std::string(cmd)+
00231              " is not implemented.\n", COLVARS_INPUT_ERROR);
00232   return -1;
00233 }
00234 
00235 
00236 int colvarscript::get_command_n_args_max(char const *cmd)
00237 {
00238   if (cmd_str_map.count(cmd) > 0) {
00239     colvarscript::command const c = cmd_str_map[std::string(cmd)];
00240     return cmd_n_args_max[c];
00241   }
00242   cvm::error("Error: command "+std::string(cmd)+
00243              " is not implemented.\n", COLVARS_INPUT_ERROR);
00244   return -1;
00245 }
00246 
00247 
00248 char const *colvarscript::get_command_full_help(char const *cmd)
00249 {
00250   if (cmd_str_map.count(cmd) > 0) {
00251     colvarscript::command const c = cmd_str_map[std::string(cmd)];
00252     return cmd_full_help[c].c_str();
00253   }
00254   cvm::error("Error: command "+std::string(cmd)+
00255              " is not implemented.\n", COLVARS_INPUT_ERROR);
00256   return NULL;
00257 }
00258 
00259 
00260 std::string colvarscript::get_command_cmdline_syntax(colvarscript::Object_type t,
00261                                                      colvarscript::command cmd)
00262 {
00263   std::string const prefix = get_cmd_prefix(t);
00264   std::string const cmdstr(cmd_names[cmd]);
00265 
00266   // Get the sub-command as used in the command line
00267   std::string const cmdline_cmd(cmdstr, prefix.size());
00268   std::string cmdline_args;
00269 
00270   size_t i;
00271   for (i = 0; i < cmd_n_args_min[cmd]; i++) {
00272     std::string const &arghelp = cmd_arghelp[cmd][i];
00273     size_t space = arghelp.find(" : ");
00274     cmdline_args += " <"+cmd_arghelp[cmd][i].substr(0, space)+">";
00275   }
00276   for (i = cmd_n_args_min[cmd]; i < cmd_n_args_max[cmd]; i++) {
00277     std::string const &arghelp = cmd_arghelp[cmd][i];
00278     size_t space = arghelp.find(" : ");
00279     cmdline_args += " ["+cmd_arghelp[cmd][i].substr(0, space)+"]";
00280   }
00281 
00282   switch (t) {
00283   case use_module:
00284     return std::string("cv "+cmdline_cmd+cmdline_args); break;
00285   case use_colvar:
00286     return std::string("cv colvar name "+cmdline_cmd+cmdline_args); break;
00287   case use_bias:
00288     return std::string("cv bias name "+cmdline_cmd+cmdline_args); break;
00289   default:
00290     // Already handled, but silence the warning
00291     return std::string("");
00292   }
00293 
00294   return std::string("");
00295 }
00296 
00297 
00298 std::string colvarscript::get_cmdline_help_summary(colvarscript::Object_type t)
00299 {
00300   std::string output;
00301   output += "List of commands:\n\n";
00302 
00303   for (size_t i = 0; i < cmd_help.size(); i++) {
00304     std::string const prefix = get_cmd_prefix(t);
00305     command const c = cmd_str_map[std::string(cmd_names[i])];
00306     if (std::string(cmd_names[i], prefix.size()) == prefix) {
00307       output += get_command_cmdline_syntax(t, c)+std::string("\n");
00308     }
00309   }
00310   if (t == use_module) {
00311     output += "\nFor detailed help on each command use:\n"
00312       "    cv help <command>\n";
00313     output += "\nTo list all commands acting on collective variables use:\n"
00314       "    cv help colvar\n";
00315     output += "\nTo list all commands acting on biases use:\n"
00316       "    cv help bias\n";
00317   }
00318   if (t == use_colvar) {
00319     output += "\nFor detailed help on each command use:\n"
00320       "    cv colvar name help <command> (\"name\" does not need to exist)\n";
00321   }
00322   if (t == use_bias) {
00323     output += "\nFor detailed help on each command use:\n"
00324       "    cv bias name help <command> (\"name\" does not need to exist)\n";
00325   }
00326   return output;
00327 }
00328 
00329 
00330 std::string colvarscript::get_command_cmdline_help(colvarscript::Object_type t,
00331                                                    std::string const &cmd)
00332 {
00333   std::string const cmdkey(get_cmd_prefix(t)+cmd);
00334   if (cmd_str_map.count(cmdkey) > 0) {
00335     command const c = cmd_str_map[cmdkey];
00336     return get_command_cmdline_syntax(t, c)+"\n\n"+
00337       get_command_full_help(cmd_names[c]);
00338   }
00339   cvm::set_error_bits(COLVARS_INPUT_ERROR);
00340   return std::string("Could not find scripting command \""+cmd+"\".");
00341 }
00342 
00343 
00344 int colvarscript::run(int objc, unsigned char *const objv[])
00345 {
00346   clear_str_result();
00347 
00348   if (cvm::debug()) {
00349     cvm::log("Called script run with " + cvm::to_str(objc) + " args:");
00350     for (int i = 0; i < objc; i++) {
00351       cvm::log(obj_to_str(objv[i]));
00352     }
00353   }
00354 
00355   if (objc < 2) {
00356     set_result_str("No commands given: use \"cv help\" "
00357                    "for a list of commands.");
00358     return COLVARSCRIPT_ERROR;
00359   }
00360 
00361   // Main command; usually "cv"
00362   std::string const main_cmd(std::string(obj_to_str(objv[0])));
00363 
00364   // Name of the (sub)command
00365   std::string const cmd(obj_to_str(objv[1]));
00366 
00367   // Build a safe-to-print command line to print in case of error
00368   std::string cmdline(main_cmd+std::string(" ")+cmd);
00369 
00370   // Pointer to the function implementing it
00371   int (*cmd_fn)(void *, int, unsigned char * const *) = NULL;
00372 
00373   // Pointer to object handling the command (the functions are C)
00374   void *obj_for_cmd = NULL;
00375 
00376   if (cmd == "colvar") {
00377 
00378     if (objc < 4) {
00379       add_error_msg("Missing parameters: use \""+main_cmd+
00380                     " help colvar\" for a summary");
00381       return COLVARSCRIPT_ERROR;
00382     }
00383     std::string const name(obj_to_str(objv[2]));
00384     std::string const subcmd(obj_to_str(objv[3]));
00385     obj_for_cmd = reinterpret_cast<void *>(cvm::colvar_by_name(name));
00386     if (obj_for_cmd == NULL) {
00387       if (subcmd != std::string("help")) {
00388         // Unless asking for help, a valid colvar name must be given
00389         add_error_msg("Colvar not found: " + name);
00390         return COLVARSCRIPT_ERROR;
00391       }
00392     }
00393     cmd_fn = get_cmd_fn(get_cmd_prefix(use_colvar)+subcmd);
00394     cmdline += std::string(" name ")+subcmd;
00395     if (objc > 4) {
00396       cmdline += " ...";
00397     }
00398 
00399   } else if (cmd == "bias") {
00400 
00401     if (objc < 4) {
00402       add_error_msg("Missing parameters: use \""+main_cmd+
00403                     " help bias\" for a summary");
00404       return COLVARSCRIPT_ERROR;
00405     }
00406     std::string const name(obj_to_str(objv[2]));
00407     std::string const subcmd(obj_to_str(objv[3]));
00408     obj_for_cmd = reinterpret_cast<void *>(cvm::bias_by_name(name));
00409     if (obj_for_cmd == NULL) {
00410       if ((subcmd == "") || (subcmd != std::string("help"))) {
00411         // Unless asking for help, a valid bias name must be given
00412         add_error_msg("Bias not found: " + name);
00413         return COLVARSCRIPT_ERROR;
00414       }
00415     }
00416     cmd_fn = get_cmd_fn(get_cmd_prefix(use_bias)+subcmd);
00417     cmdline += std::string(" name ")+subcmd;
00418     if (objc > 4) {
00419       cmdline += " ...";
00420     }
00421 
00422   } else {
00423 
00424     cmd_fn = get_cmd_fn(get_cmd_prefix(use_module)+cmd);
00425     obj_for_cmd = reinterpret_cast<void *>(this);
00426 
00427     if (objc > 2) {
00428       cmdline += " ...";
00429     }
00430   }
00431 
00432   int error_code = COLVARS_OK;
00433 
00434   // If command was found in map, execute it
00435   if (cmd_fn) {
00436     error_code = (*cmd_fn)(obj_for_cmd, objc, objv);
00437   } else {
00438     add_error_msg("Syntax error: "+cmdline+"\n"
00439                   "  Run \"cv help\" or \"cv help <command>\" "
00440                   "to get the correct syntax.\n");
00441     error_code = COLVARSCRIPT_ERROR;
00442   }
00443 
00444   return error_code;
00445 }
00446 
00447 
00448 char *colvarscript::obj_to_str(unsigned char *obj)
00449 {
00450   char *strobj = reinterpret_cast<char *>(obj);
00451   if (cvm::debug()) {
00452     cvm::log("Using simple-cast script::obj_to_str(): result = \"" +
00453              (strobj ? std::string(strobj) : std::string("(null)")) + "\"");
00454   }
00455   return strobj;
00456 }
00457 
00458 
00459 std::vector<std::string> colvarscript::obj_to_str_vector(unsigned char *obj)
00460 {
00461   if (cvm::debug()) {
00462     cvm::log("Using simple-cast colvarscript::obj_to_str_vector().\n");
00463   }
00464 
00465   std::vector<std::string> new_result;
00466   std::string const str(reinterpret_cast<char *>(obj));
00467 
00468   // TODO get rid of this once colvarscript can handle both fix_modify and Tcl?
00469   // LAMMPS has a nicer function in the utils class
00470 
00471   for (size_t i = 0; i < str.length(); i++) {
00472     char const c = str[i];
00473     if (c == '\"') {
00474       i++;
00475       if (i >= str.length()) {
00476         cvm::error("Error: could not split the following string:\n"+
00477                    str+"\n", COLVARS_INPUT_ERROR);
00478         break;
00479       }
00480       new_result.push_back(std::string(""));
00481       while (str[i] != '\"') {
00482         new_result.back().append(1, str[i]);
00483         if (i >= str.length()) {
00484           cvm::error("Error: could not split the following string:\n"+
00485                      str+"\n", COLVARS_INPUT_ERROR);
00486           break;
00487         } else {
00488           i++;
00489         }
00490       }
00491     }
00492   }
00493 
00494   if (cvm::debug()) {
00495     cvm::log("result = "+cvm::to_str(new_result)+".\n");
00496   }
00497 
00498   return new_result;
00499 }
00500 
00501 
00502 int colvarscript::proc_features(colvardeps *obj,
00503                                 int objc, unsigned char *const objv[]) {
00504 
00505   // size was already checked before calling
00506   std::string const subcmd(obj_to_str(objv[3]));
00507 
00508   if (cvm::debug()) {
00509     cvm::log("Called proc_features() with " + cvm::to_str(objc) + " args:");
00510     for (int i = 0; i < objc; i++) {
00511       cvm::log(obj_to_str(objv[i]));
00512     }
00513   }
00514 
00515   if ((subcmd == "get") || (subcmd == "set")) {
00516     std::vector<colvardeps::feature *> const &features = obj->features();
00517     std::string const req_feature(obj_to_str(objv[4]));
00518     colvardeps::feature *f = NULL;
00519     int fid = 0;
00520     for (fid = 0; fid < int(features.size()); fid++) {
00521       if (features[fid]->description ==
00522           colvarparse::to_lower_cppstr(req_feature)) {
00523         f = features[fid];
00524         break;
00525       }
00526     }
00527 
00528     if (f == NULL) {
00529 
00530       add_error_msg("Error: feature \""+req_feature+"\" does not exist.\n");
00531       return COLVARSCRIPT_ERROR;
00532 
00533     } else {
00534 
00535       if (! obj->is_available(fid)) {
00536         add_error_msg("Error: feature \""+req_feature+"\" is unavailable.\n");
00537         return COLVARSCRIPT_ERROR;
00538       }
00539 
00540       if (subcmd == "get") {
00541         set_result_str(cvm::to_str(obj->is_enabled(fid) ? 1 : 0));
00542         return COLVARS_OK;
00543       }
00544 
00545       if (subcmd == "set") {
00546         if (objc == 6) {
00547           std::string const yesno =
00548             colvarparse::to_lower_cppstr(std::string(obj_to_str(objv[5])));
00549           if ((yesno == std::string("yes")) ||
00550               (yesno == std::string("on")) ||
00551               (yesno == std::string("1"))) {
00552             obj->enable(fid);
00553             return COLVARS_OK;
00554           } else if ((yesno == std::string("no")) ||
00555               (yesno == std::string("off")) ||
00556               (yesno == std::string("0"))) {
00557             obj->disable(fid);
00558             return COLVARS_OK;
00559           }
00560         }
00561         add_error_msg("Missing value when setting feature \""+req_feature+
00562                       "\".\n");
00563         return COLVARSCRIPT_ERROR;
00564       }
00565     }
00566   }
00567 
00568   // This shouldn't be reached any more
00569   return COLVARSCRIPT_ERROR;
00570 }
00571 
00572 
00573 int colvarscript::unsupported_op()
00574 {
00575   return cvm::error("Error: unsupported script operation.\n",
00576                     COLVARS_NOT_IMPLEMENTED);
00577 }
00578 
00579 
00580 int colvarscript::set_result_str(std::string const &s)
00581 {
00582   if (cvm::get_error() != COLVARS_OK) {
00583     // Avoid overwriting the error message
00584     modify_str_result() += s;
00585   } else {
00586     modify_str_result() = s;
00587   }
00588   return COLVARS_OK;
00589 }
00590 
00591 
00592 void colvarscript::add_error_msg(std::string const &s)
00593 {
00594   modify_str_result() += s;
00595   // Ensure terminating newlines
00596   if (s[s.size()-1] != '\n') {
00597     modify_str_result() += "\n";
00598   }
00599 }
00600 
00601 
00602 int colvarscript::clear_str_result()
00603 {
00604   modify_str_result().clear();
00605   return COLVARS_OK;
00606 }
00607 
00608 
00609 extern "C"
00610 int run_colvarscript_command(int objc, unsigned char *const objv[])
00611 {
00612   colvarmodule *cv = cvm::main();
00613   colvarscript *script = cv ? cv->proxy->script : NULL;
00614   if (!script) {
00615     cvm::error("Called run_colvarscript_command without a script object.\n",
00616                COLVARS_BUG_ERROR);
00617     return -1;
00618   }
00619   int retval = script->run(objc, objv);
00620   return retval;
00621 }
00622 
00623 
00624 extern "C"
00625 const char * get_colvarscript_result()
00626 {
00627   colvarscript *script = colvarscript_obj();
00628   if (!script) {
00629     cvm::error("Called get_colvarscript_result without a script object.\n");
00630     return NULL;
00631   }
00632   return script->str_result().c_str();
00633 }
00634 
00635 
00636 #if defined(COLVARS_TCL)
00637 
00638 #if defined(VMDTCL)
00639 // Function used by VMD to set up the module
00640 int tcl_colvars_vmd_init(Tcl_Interp *interp, int molid);
00641 #endif
00642 
00643 #if !defined(VMDTCL) && !defined(NAMD_TCL)
00644 // Initialize Colvars when loaded as a shared library into Tcl interpreter
00645 extern "C" {
00646   int Colvars_Init(Tcl_Interp *interp) {
00647     colvarproxy *proxy = new colvarproxy();
00648     colvarmodule *colvars = new colvarmodule(proxy);
00649     proxy->set_tcl_interp(interp);
00650     proxy->colvars = colvars;
00651     Tcl_CreateObjCommand(interp, "cv", tcl_run_colvarscript_command,
00652                          (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
00653     Tcl_EvalEx(interp, "package provide colvars", -1, 0);
00654     return TCL_OK;
00655   }
00656 }
00657 #endif
00658 
00659 
00660 extern "C" int tcl_run_colvarscript_command(ClientData /* clientData */,
00661                                             Tcl_Interp *my_interp,
00662                                             int objc, Tcl_Obj *const objv[])
00663 {
00664   colvarmodule *colvars = cvm::main();
00665 
00666   if (!colvars) {
00667 #if defined(VMDTCL)
00668 
00669     if (objc == 2) {
00670       if (!strcmp(Tcl_GetString(objv[1]), "molid")) {
00671         // return invalid molid
00672         Tcl_SetResult(my_interp, (char *) "-1", TCL_STATIC);
00673       }
00674       if (!strcmp(Tcl_GetString(objv[1]), "delete") ||
00675           !strcmp(Tcl_GetString(objv[1]), "reset")) {
00676         // nothing to delete or reset
00677         Tcl_SetResult(my_interp, NULL, TCL_STATIC);
00678       }
00679       if (!strcmp(Tcl_GetString(objv[1]), "help")) {
00680         // print message
00681         Tcl_SetResult(my_interp,
00682                       (char *) "First, setup the Colvars module with: "
00683                       "cv molid <id>|top", TCL_STATIC);
00684       }
00685       return TCL_OK;
00686     }
00687 
00688     if (objc >= 3) {
00689       // require a molid to create the module
00690       if (!strcmp(Tcl_GetString(objv[1]), "molid")) {
00691         int molid = -(1<<16); // This value is used to indicate "top"
00692         if (strcmp(Tcl_GetString(objv[2]), "top")) {
00693           // If this is not "top", get the integer value
00694           Tcl_GetIntFromObj(my_interp, objv[2], &molid);
00695         }
00696         return tcl_colvars_vmd_init(my_interp, molid);
00697       } else {
00698         Tcl_SetResult(my_interp, (char *) "Syntax error.  First, setup the Colvars module with cv molid <id>|top", TCL_STATIC);
00699         return TCL_ERROR;
00700       }
00701     }
00702 
00703     Tcl_SetResult(my_interp, (char *) "First, setup the Colvars module with: "
00704                   "cv molid <id>|top", TCL_STATIC);
00705 
00706 #else
00707     Tcl_SetResult(my_interp,
00708                   const_cast<char *>("Error: Colvars module not yet initialized"),
00709                   TCL_STATIC);
00710 #endif
00711     return TCL_ERROR;
00712   }
00713 
00714   colvarproxy *proxy = colvars->proxy;
00715   Tcl_Interp *interp = my_interp ? my_interp : proxy->get_tcl_interp();
00716   colvarscript *script = colvarscript_obj();
00717   if (!script) {
00718     char const *errstr = "Called tcl_run_colvarscript_command "
00719       "without a Colvars script interface set up.\n";
00720     Tcl_SetResult(interp, const_cast<char *>(errstr), TCL_VOLATILE);
00721     return TCL_ERROR;
00722   }
00723 
00724   cvm::clear_error();
00725 
00726   unsigned char * arg_pointers_[100];
00727   if (objc > 100) {
00728     std::string const errstr = "Too many positional arguments ("+
00729       cvm::to_str(objc)+") passed to the \"cv\" command.\n";
00730     Tcl_SetResult(interp, const_cast<char *>(errstr.c_str()), TCL_VOLATILE);
00731     return TCL_ERROR;
00732   }
00733   for (int i = 0; i < objc; i++) {
00734     arg_pointers_[i] = reinterpret_cast<unsigned char *>(const_cast<char *>(proxy->tcl_get_str(objv[i])));
00735   }
00736   int retval = script->run(objc, arg_pointers_);
00737 
00738   std::string result = proxy->get_error_msgs() + script->str_result();
00739 
00740   Tcl_SetResult(interp, const_cast<char *>(result.c_str()),
00741                 TCL_VOLATILE);
00742 
00743   if (proxy->delete_requested()) {
00744     if (!proxy->simulation_running()) {
00745       // Running in VMD
00746       Tcl_SetResult(interp,
00747                     const_cast<char *>("Deleting Colvars module"
00748                                        ": to recreate, use cv molid <molecule ID>"),
00749                     TCL_STATIC);
00750     }
00751     delete proxy;
00752     proxy = NULL;
00753   }
00754 
00755   return (retval == COLVARS_OK) ? TCL_OK : TCL_ERROR;
00756 }
00757 
00758 #endif // #if defined(COLVARS_TCL)
00759 
00760 
00761 
00762 
00763 int colvarscript::set_result_text_from_str(std::string const &x_str,
00764                                            unsigned char *obj) {
00765   if (obj) {
00766     strcpy(reinterpret_cast<char *>(obj), x_str.c_str());
00767   } else {
00768     set_result_str(x_str);
00769   }
00770   return COLVARS_OK;
00771 }
00772 
00773 // Template to convert everything to string and use the above
00774 
00775 template <typename T>
00776 int colvarscript::set_result_text(T const &x, unsigned char *obj) {
00777   std::string const x_str = x.to_simple_string();
00778   return set_result_text_from_str(x_str, obj);
00779 }
00780 
00781 
00782 template <typename T>
00783 int colvarscript::pack_vector_elements_text(std::vector<T> const &x,
00784                                             std::string &x_str) {
00785   x_str.clear();
00786   for (size_t i = 0; i < x.size(); ++i) {
00787     if (i > 0) x_str.append(1, ' ');
00788     x_str += cvm::to_str(x[i]);
00789   }
00790   return COLVARS_OK;
00791 }
00792 
00793 
00794 // Specializations for plain old data types that don't have a stringifier member
00795 
00796 template <>
00797 int colvarscript::set_result_text(int const &x, unsigned char *obj) {
00798   std::string const x_str = cvm::to_str(x);
00799   return set_result_text_from_str(x_str, obj);
00800 }
00801 
00802 template <>
00803 int colvarscript::set_result_text(std::vector<int> const &x,
00804                                   unsigned char *obj) {
00805   std::string x_str("");
00806   pack_vector_elements_text<int>(x, x_str);
00807   return set_result_text_from_str(x_str, obj);
00808 }
00809 
00810 
00811 template <>
00812 int colvarscript::set_result_text(long int const &x, unsigned char *obj) {
00813   std::string const x_str = cvm::to_str(x);
00814   return set_result_text_from_str(x_str, obj);
00815 }
00816 
00817 template <>
00818 int colvarscript::set_result_text(std::vector<long int> const &x,
00819                                   unsigned char *obj) {
00820   std::string x_str("");
00821   pack_vector_elements_text<long int>(x, x_str);
00822   return set_result_text_from_str(x_str, obj);
00823 }
00824 
00825 
00826 template <>
00827 int colvarscript::set_result_text(cvm::real const &x, unsigned char *obj) {
00828   std::string const x_str = cvm::to_str(x);
00829   return set_result_text_from_str(x_str, obj);
00830 }
00831 
00832 template <>
00833 int colvarscript::set_result_text(std::vector<cvm::real> const &x,
00834                                   unsigned char *obj) {
00835   std::string x_str("");
00836   pack_vector_elements_text<cvm::real>(x, x_str);
00837   return set_result_text_from_str(x_str, obj);
00838 }
00839 
00840 
00841 // TODO these can be removed after the Tcl backend is ready (otherwise, the
00842 // default template syntax may break scripts or the Dashboard)
00843 
00844 template <>
00845 int colvarscript::set_result_text(std::vector<cvm::rvector> const &x,
00846                                   unsigned char *obj) {
00847   std::string x_str("");
00848   for (size_t i = 0; i < x.size(); i++) {
00849     if (i > 0) x_str.append(1, ' ');
00850     x_str += "{ "+x[i].to_simple_string()+" }";
00851   }
00852   return set_result_text_from_str(x_str, obj);
00853 }
00854 
00855 template <>
00856 int colvarscript::set_result_text(std::vector<colvarvalue> const &x,
00857                                   unsigned char *obj) {
00858   std::string x_str("");
00859   for (size_t i = 0; i < x.size(); i++) {
00860     if (i > 0) x_str.append(1, ' ');
00861     x_str += "{ "+x[i].to_simple_string()+" }";
00862   }
00863   return set_result_text_from_str(x_str, obj);
00864 }
00865 
00866 
00867 // Member functions to set script results for each typexc
00868 
00869 int colvarscript::set_result_int(int const &x, unsigned char *obj) {
00870   return set_result_text<int>(x, obj);
00871 }
00872 
00873 int colvarscript::set_result_int_vec(std::vector<int> const &x,
00874                                      unsigned char *obj) {
00875   return set_result_text< std::vector<int> >(x, obj);
00876 }
00877 
00878 
00879 int colvarscript::set_result_long_int(long int const &x, unsigned char *obj) {
00880   return set_result_text<long int>(x, obj);
00881 }
00882 
00883 int colvarscript::set_result_long_int_vec(std::vector<long int> const &x,
00884                                           unsigned char *obj) {
00885   return set_result_text< std::vector<long int> >(x, obj);
00886 }
00887 
00888 
00889 int colvarscript::set_result_real(cvm::real const &x, unsigned char *obj) {
00890   return set_result_text<cvm::real>(x, obj);
00891 }
00892 
00893 int colvarscript::set_result_real_vec(std::vector<cvm::real> const &x,
00894                                       unsigned char *obj) {
00895   return set_result_text< std::vector<cvm::real> >(x, obj);
00896 }
00897 
00898 
00899 int colvarscript::set_result_rvector(cvm::rvector const &x, unsigned char *obj) {
00900   return set_result_text<cvm::rvector>(x, obj);
00901 }
00902 
00903 int colvarscript::set_result_rvector_vec(std::vector<cvm::rvector> const &x,
00904                                          unsigned char *obj) {
00905   return set_result_text< std::vector<cvm::rvector> >(x, obj);
00906 }
00907 
00908 
00909 int colvarscript::set_result_colvarvalue(colvarvalue const &x,
00910                                          unsigned char *obj) {
00911   return set_result_text<colvarvalue>(x, obj);
00912 }
00913 
00914 int colvarscript::set_result_colvarvalue_vec(std::vector<colvarvalue> const &x,
00915                                              unsigned char *obj) {
00916   return set_result_text< std::vector<colvarvalue> >(x, obj);
00917 }

Generated on Thu Mar 28 02:42:57 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002