TclCommand.cc

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2004 Intel Corporation. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  * 
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 #include "TclCommand.h"
00039 #include "HelpCommand.h"
00040 #include "DebugCommand.h"
00041 #include "LogCommand.h"
00042 
00043 #include "debug/DebugUtils.h"
00044 #include "io/NetUtils.h"
00045 #include "thread/SpinLock.h"
00046 #include "util/StringBuffer.h"
00047 #include "util/InitSequencer.h"
00048 
00049 namespace oasys {
00050 
00051 /******************************************************************************
00052  *
00053  * TclCommandInterp
00054  *
00055  *****************************************************************************/
00056 // static variables
00057 TclCommandInterp* TclCommandInterp::instance_;
00058 TclCommandList*   TclCommandInterp::auto_reg_ = NULL;
00059 
00060 #include "command-init-tcl.c"
00061 
00062 TclCommandInterp::TclCommandInterp()
00063     : Logger("TclCommandInterp", "/command")
00064 {}
00065 
00066 int
00067 TclCommandInterp::do_init(char* argv0, bool no_default_cmds)
00068 {
00069     interp_ = Tcl_CreateInterp();
00070     lock_   = new SpinLock();
00071     Tcl_Preserve(interp_);
00072 
00073     // for some reason, this needs to be called to set up the various
00074     // locale strings and get things like the "ascii" encoding defined
00075     // for a file channel
00076     Tcl_FindExecutable(argv0);
00077     
00078     // run Tcl_Init to set up the local tcl package path, but don't
00079     // depend on it succeeding in case there's a strange tcl
00080     // installation
00081     if (Tcl_Init(interp_) != TCL_OK) {
00082         StringBuffer err("initialization problem calling Tcl_Init: %s\n"
00083                          "(this is not a fatal error, continuing initialization...)\n\n",
00084                          interp_->result);
00085         log_multiline(LOG_WARN, err.c_str());
00086     }
00087 
00088     // do auto registration of commands (if any)
00089     if (auto_reg_) {
00090         ASSERT(auto_reg_); 
00091         while (!auto_reg_->empty()) {
00092             TclCommand* m = auto_reg_->front();
00093             auto_reg_->pop_front();
00094             reg(m);
00095         }
00096     
00097         delete auto_reg_;
00098         auto_reg_ = NULL;
00099     }
00100 
00101     // register the default commands
00102     if (! no_default_cmds) {
00103         HelpCommand* help = new HelpCommand();
00104         reg(help);
00105 
00106         LogCommand* log = new LogCommand();
00107         reg(log);
00108 
00109         DebugCommand* debug = new DebugCommand();
00110         reg(debug);
00111     }
00112     
00113     // evaluate the boot-time tcl commands (copied since tcl may
00114     // overwrite the string value)
00115     char* cmd = strdup(INIT_COMMAND);
00116     if (Tcl_Eval(interp_, cmd) != TCL_OK) {
00117         log_err("error in init commands: \"%s\"", interp_->result);
00118         return TCL_ERROR;
00119     }
00120     free(cmd);
00121 
00122     return TCL_OK;
00123 }
00124 
00125 TclCommandInterp::~TclCommandInterp()
00126 {
00127     log_notice("shutting down interpreter");
00128     TclCommandList::iterator iter;
00129     for (iter = commands_.begin();
00130          iter != commands_.end();
00131          ++iter)
00132     {
00133         log_debug("deleting %s command", (*iter)->name_.c_str());
00134         delete *iter;
00135     }
00136 
00137     log_debug("all commands deleted");
00138 
00139     commands_.clear();
00140 
00141     Tcl_DeleteInterp(interp_);
00142     Tcl_Release(interp_);
00143 
00144     delete lock_;
00145 }
00146 
00147 void
00148 TclCommandInterp::shutdown()
00149 {
00150     delete instance_;
00151     instance_ = NULL;
00152 }
00153 
00154 int
00155 TclCommandInterp::init(char* argv0, bool no_default_cmds)
00156 {
00157     ASSERT(instance_ == NULL);
00158     instance_ = new TclCommandInterp();
00159     
00160     return instance_->do_init(argv0, no_default_cmds);
00161 }
00162 
00163 int
00164 TclCommandInterp::exec_file(const char* file)
00165 {
00166     int err;
00167     ScopeLock l(lock_, "TclCommandInterp::exec_file");
00168 
00169     log_debug("executing command file %s", file);
00170     
00171     err = Tcl_EvalFile(interp_, (char*)file);
00172     
00173     if (err != TCL_OK) {
00174         logf(LOG_ERR, "error: line %d: '%s':\n%s",
00175              interp_->errorLine, Tcl_GetStringResult(interp_),
00176              Tcl_GetVar(interp_, "errorInfo", TCL_GLOBAL_ONLY));
00177     }
00178     
00179     return err;    
00180 }
00181 
00182 int
00183 TclCommandInterp::exec_command(const char* command)
00184 {
00185     int err;
00186     ScopeLock l(lock_, "TclCommandInterp::exec_command");
00187 
00188     // ignore empty command lines
00189     if (command[0] == '\0')
00190         return TCL_OK;
00191 
00192     // tcl modifies the command string while executing it, so we need
00193     // to make a copy
00194     char* buf = strdup(command);
00195 
00196     log_debug("executing command '%s'", buf);
00197     
00198     err = Tcl_Eval(interp_, buf);
00199     
00200     free(buf);
00201     
00202     if (err != TCL_OK) {
00203         logf(LOG_ERR, "error: line %d: '%s':\n%s",
00204              interp_->errorLine, Tcl_GetStringResult(interp_),
00205              Tcl_GetVar(interp_, "errorInfo", TCL_GLOBAL_ONLY));
00206     }
00207     
00208     return err;
00209 }
00210 
00211 void
00212 TclCommandInterp::command_server(const char* prompt,
00213                                  in_addr_t addr, u_int16_t port)
00214 {
00215     log_debug("starting command server on %s:%d", intoa(addr), port);
00216     StringBuffer cmd("command_server \"%s\" %s %d", prompt, intoa(addr), port);
00217     
00218     if (Tcl_Eval(interp_, const_cast<char*>(cmd.c_str())) != TCL_OK) {
00219         log_err("tcl error starting command_server: \"%s\"",
00220                 interp_->result);
00221     }
00222 }
00223 
00224 void
00225 TclCommandInterp::command_loop(const char* prompt)
00226 {
00227     StringBuffer cmd("command_loop \"%s\"", prompt);
00228     
00229     if (Tcl_Eval(interp_, const_cast<char*>(cmd.c_str())) != TCL_OK) {
00230         log_err("tcl error in command_loop: \"%s\"", interp_->result);
00231     }
00232 }
00233 
00234 void
00235 TclCommandInterp::event_loop()
00236 {
00237     if (Tcl_Eval(interp_, "event_loop") != TCL_OK) {
00238         log_err("tcl error in event_loop: \"%s\"", interp_->result);
00239     }
00240 }
00241 
00242 void
00243 TclCommandInterp::exit_event_loop()
00244 {
00245     if (Tcl_Eval(interp_, "exit_event_loop") != TCL_OK) {
00246         log_err("tcl error in event_loop: \"%s\"", interp_->result);
00247     }
00248 }
00249 
00250 void
00251 TclCommandInterp::reg(TclCommand *command)
00252 {
00253     ScopeLock l(lock_, "TclCommandInterp::reg");
00254     
00255     command->logf(LOG_DEBUG, "%s command registering", command->name());
00256 
00257     Tcl_CmdInfo info;
00258     if (Tcl_GetCommandInfo(interp_, (char*)command->name(), &info) != 0) {
00259         log_warn("re-registering command %s over existing command",
00260                  command->name());
00261     }
00262                  
00263     Tcl_CreateObjCommand(interp_, 
00264                          const_cast<char*>(command->name()),
00265                          TclCommandInterp::tcl_cmd,
00266                          (ClientData)command,
00267                          NULL);
00268     
00269     commands_.push_front(command);
00270 }
00271 
00272 bool
00273 TclCommandInterp::lookup(const char* command, TclCommand** commandp)
00274 {
00275     Tcl_CmdInfo info;
00276 
00277     if (Tcl_GetCommandInfo(interp_, (char*)command, &info) == 0) {
00278         log_debug("lookup tcl command %s: does not exist", command);
00279         return false;
00280     }
00281 
00282     if (info.objProc == TclCommandInterp::tcl_cmd) {
00283         log_debug("lookup tcl command %s: exists and is TclCommand %p",
00284                   command, info.clientData);
00285         
00286         if (commandp)
00287             *commandp = (TclCommand*)info.objClientData;
00288         
00289     } else {
00290         log_debug("lookup tcl command %s: exists but is not a TclCommand",
00291                   command);
00292     }
00293 
00294     return true;
00295 }
00296 
00297 void
00298 TclCommandInterp::auto_reg(TclCommand *command)
00299 {
00300     // this should only be called from the static initializers, i.e.
00301     // we haven't been initialized yet
00302     ASSERT(instance_ == NULL);
00303 
00304     // we need to explicitly create the auto_reg list the first time
00305     // since there's no guarantee of ordering of static constructors
00306     if (!auto_reg_)
00307         auto_reg_ = new TclCommandList();
00308     
00309     auto_reg_->push_back(command);
00310 }
00311 
00312 void
00313 TclCommandInterp::reg_atexit(void(*fn)(void*), void* data)
00314 {
00315     ScopeLock l(lock_, "TclCommandInterp::reg_atexit");
00316     Tcl_CreateExitHandler(fn, data);
00317 }
00318     
00319 int 
00320 TclCommandInterp::tcl_cmd(ClientData client_data, Tcl_Interp* interp,
00321                           int objc, Tcl_Obj* const* objv)
00322 {
00323     TclCommand* command = (TclCommand*)client_data;
00324 
00325     // first check for builtin commands
00326     if (command->do_builtins_) 
00327     {
00328         if (objc == 2) 
00329         {
00330             const char* cmd = Tcl_GetStringFromObj(objv[1], NULL);
00331             if (strcmp(cmd, "info") == 0) {
00332                 return command->cmd_info(interp);
00333             }
00334         }
00335         else if (objc > 2) 
00336         {
00337             const char* cmd = Tcl_GetStringFromObj(objv[1], NULL);
00338             if (strcmp(cmd, "set") == 0) {
00339                 return command->cmd_set(objc, (Tcl_Obj**)objv, interp);
00340             }
00341         }
00342     }
00343 
00344     return command->exec(objc, (Tcl_Obj**)objv, interp);
00345 }
00346 
00347 void
00348 TclCommandInterp::set_result(const char* result)
00349 {
00350     Tcl_SetResult(interp_, (char*)result, TCL_VOLATILE);
00351 }
00352 
00353 void
00354 TclCommandInterp::set_objresult(Tcl_Obj* obj)
00355 {
00356     Tcl_SetObjResult(interp_, obj);
00357 }
00358 
00359 void
00360 TclCommandInterp::append_result(const char* result)
00361 {
00362     Tcl_AppendResult(interp_, (char*)result, NULL);
00363 }
00364 
00365 void
00366 TclCommandInterp::vresultf(const char* fmt, va_list ap, bool append)
00367 {
00368     StringBuffer buf;
00369     buf.vappendf(fmt, ap);
00370     
00371     if (append) {
00372         Tcl_AppendResult(interp_, buf.c_str(), NULL);
00373     } else {
00374         Tcl_SetResult(interp_, const_cast<char*>(buf.c_str()), TCL_VOLATILE);
00375     }
00376 }
00377 
00378 void
00379 TclCommandInterp::resultf(const char* fmt, ...)
00380 {
00381     va_list ap;
00382     va_start(ap, fmt);
00383     vresultf(fmt, ap, false);
00384     va_end(ap);
00385 }
00386 
00387 void
00388 TclCommandInterp::append_resultf(const char* fmt, ...)
00389 {
00390     va_list ap;
00391     va_start(ap, fmt);
00392     vresultf(fmt, ap, true);
00393     va_end(ap);
00394 }
00395 
00396 void
00397 TclCommandInterp::wrong_num_args(int argc, const char** argv, int parsed,
00398                                  int min, int max)
00399 {
00400     set_result("wrong number of arguments to '");
00401     append_result(argv[0]);
00402     
00403     for (int i = 1; i < parsed; ++i) {
00404         append_result(" ");
00405         append_result(argv[i]);
00406     }
00407     append_result("'");
00408 
00409     if (max == min) {
00410         append_resultf(" expected %d, got %d", min, argc);
00411     } else if (max == INT_MAX) {
00412         append_resultf(" expected at least %d, got %d", min, argc);
00413     } else {
00414         append_resultf(" expected %d - %d, got %d", min, max, argc);
00415     }
00416 }
00417 
00418 void
00419 TclCommandInterp::wrong_num_args(int objc, Tcl_Obj** objv, int parsed,
00420                                  int min, int max)
00421 {
00422     char* argv[objc];
00423     for (int i = 0; i < objc; ++i) {
00424         argv[i] = Tcl_GetStringFromObj(objv[i], NULL);
00425     }
00426     wrong_num_args(objc, (const char**)argv, parsed, min, max);
00427 }
00428 
00429 const char*
00430 TclCommandInterp::get_result()
00431 {
00432     return Tcl_GetStringResult(interp_);
00433 }
00434 
00435 /******************************************************************************
00436  *
00437  * TclCommand
00438  *
00439  *****************************************************************************/
00440 TclCommand::TclCommand(const char* name, const char* theNamespace)
00441     : Logger("TclCommand", "/command/%s", name),
00442       do_builtins_(true)
00443 {
00444 
00445     if (theNamespace != 0) {
00446         name_ += theNamespace;
00447         name_ += "::";
00448     }
00449 
00450     name_ += name;
00451 }
00452 
00453 TclCommand::~TclCommand()
00454 {
00455     BindingTable::iterator iter;
00456     for (iter = bindings_.begin(); iter != bindings_.end(); ++iter) {
00457         delete iter->second;
00458     }
00459     bindings_.clear();
00460 }
00461 
00462 int
00463 TclCommand::exec(int objc, Tcl_Obj** objv, Tcl_Interp* interp)
00464 {
00465     // If the default implementation is called, then convert all
00466     // arguments to strings and then call the other exec variant.
00467     char* argv[objc];
00468 
00469     for (int i = 0; i < objc; ++i) {
00470         argv[i] = Tcl_GetStringFromObj(objv[i], NULL);
00471     }
00472 
00473     return exec(objc, (const char**) argv, interp);
00474 }
00475 
00476 int
00477 TclCommand::exec(int argc, const char** argv, Tcl_Interp* interp)
00478 {
00479     (void)argc;
00480     (void)interp;
00481     
00482     resultf("command %s unknown argument", argv[0]);
00483     return TCL_ERROR;
00484 }
00485 
00486 void
00487 TclCommand::resultf(const char* fmt, ...)
00488 {
00489     va_list ap;
00490     va_start(ap, fmt);
00491     TclCommandInterp::instance()->vresultf(fmt, ap, false);
00492     va_end(ap);
00493 }
00494 
00495 void
00496 TclCommand::append_resultf(const char* fmt, ...)
00497 {
00498     va_list ap;
00499     va_start(ap, fmt);
00500     TclCommandInterp::instance()->vresultf(fmt, ap, true);
00501     va_end(ap);
00502 }
00503 
00504 
00505 int
00506 TclCommand::cmd_info(Tcl_Interp* interp)
00507 {
00508     (void)interp;
00509     
00510     StringBuffer buf;
00511 
00512     for (BindingTable::iterator itr = bindings_.begin();
00513          itr != bindings_.end(); ++itr)
00514     {
00515         buf.appendf("%s ", (*itr).first.c_str());
00516     }
00517     
00518     set_result(buf.c_str());
00519     return TCL_OK;
00520 }
00521 
00522 int
00523 TclCommand::cmd_set(int objc, Tcl_Obj** objv, Tcl_Interp* interp)
00524 {
00525     ASSERT(objc >= 2);
00526     
00527     // handle "set binding [value]" command
00528     if (objc < 3 || objc > 4) {
00529         resultf("wrong number of args: expected 3-4, got %d", objc);
00530         return TCL_ERROR;
00531     }
00532 
00533     const char* var = Tcl_GetStringFromObj(objv[2], NULL);
00534     Tcl_Obj* val = objv[3];
00535     
00536     BindingTable::iterator itr;
00537     itr = bindings_.find(var);
00538     
00539     if (itr == bindings_.end()) {
00540         resultf("set: binding for %s does not exist", var);
00541         return TCL_ERROR;
00542     }
00543 
00544     // set value (if any)
00545     Binding* b = (*itr).second;
00546 
00547     if (objc == 4) 
00548     {
00549         switch(b->type_) 
00550         {
00551         case BINDING_INT:
00552             if (Tcl_GetIntFromObj(interp, val, b->val_.intval_) != TCL_OK) {
00553                 resultf("%s set: %s not an integer value",
00554                         Tcl_GetStringFromObj(objv[0], 0),
00555                         Tcl_GetStringFromObj(val, 0));
00556                 return TCL_ERROR;
00557             }
00558             break;
00559             
00560         case BINDING_INT16:
00561             int intval;
00562             if (Tcl_GetIntFromObj(interp, val, &intval) != TCL_OK) {
00563                 resultf("%s set: %s not an integer value",
00564                         Tcl_GetStringFromObj(objv[0], 0),
00565                         Tcl_GetStringFromObj(val, 0));
00566                 return TCL_ERROR;
00567             }
00568 
00569             if (intval > 0xffff) {
00570                 resultf("%s set: %s too big for short integer",
00571                         Tcl_GetStringFromObj(objv[0], 0),
00572                         Tcl_GetStringFromObj(val, 0));
00573                 return TCL_ERROR;
00574             }
00575                         
00576             *(b->val_.int16val_) = intval;
00577             break;
00578             
00579         case BINDING_DOUBLE:
00580             if (Tcl_GetDoubleFromObj(interp, val, b->val_.doubleval_) != TCL_OK) {
00581                 resultf("%s set: %s not an double value",
00582                         Tcl_GetStringFromObj(objv[0], 0),
00583                         Tcl_GetStringFromObj(val, 0));
00584                 return TCL_ERROR;
00585             }
00586             break;
00587             
00588         case BINDING_BOOL:
00589             int boolval;
00590             if (Tcl_GetBooleanFromObj(interp, val, &boolval) != TCL_OK) {
00591                 resultf("%s set: %s not an integer value",
00592                         Tcl_GetStringFromObj(objv[0], 0),
00593                         Tcl_GetStringFromObj(val, 0));
00594                 return TCL_ERROR;
00595             }
00596             *(b->val_.boolval_) = boolval;
00597             break;
00598             
00599         case BINDING_ADDR:
00600         {
00601             char* addr = Tcl_GetStringFromObj(val, 0);
00602             if (gethostbyname(addr, b->val_.addrval_) != 0) {
00603                 resultf("%s set: invalid value '%s' for addr", 
00604                         Tcl_GetStringFromObj(objv[0], 0), addr);
00605                 return TCL_ERROR;
00606             }
00607             break;
00608 
00609         }    
00610         case BINDING_STRING:
00611             b->val_.stringval_->assign(Tcl_GetStringFromObj(val, 0));
00612             break;
00613             
00614         default:
00615             logf(LOG_CRIT, "unimplemented binding type %d", b->type_);
00616             ASSERT(0);
00617         }
00618     }
00619 
00620     switch(b->type_) 
00621     {
00622     case BINDING_INT:
00623         resultf("%d", *(b->val_.intval_));
00624         break;
00625 
00626     case BINDING_INT16:
00627         resultf("%d", *(b->val_.int16val_));
00628         break;
00629 
00630     case BINDING_DOUBLE:
00631         resultf("%f", *(b->val_.doubleval_));
00632         break;
00633 
00634     case BINDING_BOOL:
00635         if (*(b->val_.boolval_))
00636             set_result("true");
00637         else
00638             set_result("false");
00639         break;
00640         
00641     case BINDING_ADDR:
00642         resultf("%s", intoa(*(b->val_.addrval_)));
00643         break;
00644         
00645     case BINDING_STRING:
00646         set_result(b->val_.stringval_->c_str());
00647         break;
00648         
00649     default:
00650         logf(LOG_CRIT, "unimplemented binding type %d", b->type_);
00651         ASSERT(0);
00652     }
00653     
00654     return 0;
00655 }
00656 
00657 // boilerplate code
00658 #define BIND_FUNCTIONS(_fn, _type, _typecode)                           \
00659 void                                                                    \
00660 _fn(const char* name, _type* val, const char* help)                     \
00661 {                                                                       \
00662     if (bindings_.find(name) != bindings_.end())                        \
00663     {   if (Log::initialized()) {                                       \
00664             log_warn("warning, binding for %s already exists", name);   \
00665         }                                                               \
00666     }                                                                   \
00667                                                                         \
00668     if (Log::initialized()) {                                           \
00669         log_debug("creating %s binding for %s -> %p",                   \
00670                   #_type, name, val);                                   \
00671     }                                                                   \
00672                                                                         \
00673     bindings_[name] = new Binding(_typecode, val);                      \
00674     StringBuffer subcmd("set %s", name);                                \
00675     add_to_help(subcmd.c_str(), help);                                  \
00676 }                                                                       \
00677                                                                         \
00678 void                                                                    \
00679 _fn(const char* name, _type* val, _type initval, const char* help)      \
00680 {                                                                       \
00681     *val = initval;                                                     \
00682     if (bindings_.find(name) != bindings_.end())                        \
00683     {                                                                   \
00684         if (Log::initialized()) {                                       \
00685             log_warn("warning, binding for %s already exists", name);   \
00686         }                                                               \
00687     }                                                                   \
00688                                                                         \
00689                                                                         \
00690     if (Log::initialized()) {                                           \
00691         log_debug("creating %s binding for %s -> %p",                   \
00692                   #_type, name, val);                                   \
00693     }                                                                   \
00694                                                                         \
00695     bindings_[name] = new Binding(_typecode, val);                      \
00696     StringBuffer subcmd("set %s", name);                                \
00697     add_to_help(subcmd.c_str(), help);                                  \
00698 }
00699 
00700 BIND_FUNCTIONS(TclCommand::bind_i, int, BINDING_INT);
00701 BIND_FUNCTIONS(TclCommand::bind_i, int16_t, BINDING_INT16);
00702 BIND_FUNCTIONS(TclCommand::bind_d, double, BINDING_DOUBLE);
00703 BIND_FUNCTIONS(TclCommand::bind_b, bool, BINDING_BOOL);
00704 BIND_FUNCTIONS(TclCommand::bind_addr, in_addr_t, BINDING_ADDR);
00705 
00706 void
00707 TclCommand::bind_s(const char* name, std::string* val,
00708                    const char* initval, const char* help)
00709 {
00710     if (initval)
00711         val->assign(initval);
00712     
00713     if (bindings_.find(name) != bindings_.end()) {
00714         if (Log::initialized()) {
00715             log_warn("warning, binding for %s already exists", name);
00716         }
00717     }
00718 
00719     if (Log::initialized()) {
00720         log_debug("creating string binding for %s -> %p", name, val);
00721     }
00722 
00723     bindings_[name] = new Binding(BINDING_STRING, val);
00724     StringBuffer subcmd("set %s", name);
00725     add_to_help(subcmd.c_str(), help);
00726 }
00727 
00728 void
00729 TclCommand::unbind(const char* name)
00730 {
00731     BindingTable::iterator iter = bindings_.find(name);
00732 
00733     if (iter == bindings_.end()) {
00734         if (Log::initialized()) {
00735             log_warn("warning, binding for %s doesn't exist", name);
00736         }
00737         return;
00738     }
00739 
00740     if (Log::initialized()) {
00741         log_debug("removing binding for %s", name);
00742     }
00743 
00744     Binding* old = iter->second;
00745     bindings_.erase(iter);
00746 
00747     delete old;
00748 }
00749 
00750 } // namespace oasys

Generated on Fri Dec 22 14:48:01 2006 for DTN Reference Implementation by  doxygen 1.5.1