00001 //---------------------------------------------------------------------------- 00002 /** @file SgGtpCommands.cpp 00003 See SgGtpCommands.h 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #include "SgSystem.h" 00008 #include "SgGtpCommands.h" 00009 00010 #include <iomanip> 00011 #include <iostream> 00012 #include <unistd.h> 00013 #include "SgDebug.h" 00014 #include "SgRandom.h" 00015 #include "SgTime.h" 00016 00017 using namespace std; 00018 00019 //---------------------------------------------------------------------------- 00020 00021 namespace { 00022 00023 string ParseCpuTimeId(const GtpCommand& cmd) 00024 { 00025 cmd.CheckNuArgLessEqual(1); 00026 if (cmd.NuArg() > 0) 00027 return cmd.Arg(0); 00028 return "total"; 00029 } 00030 00031 SgTimeMode TimeModeArg(const GtpCommand& cmd, size_t number) 00032 { 00033 string arg = cmd.ArgToLower(number); 00034 if (arg == "cpu") 00035 return SG_TIME_CPU; 00036 if (arg == "real") 00037 return SG_TIME_REAL; 00038 throw GtpFailure() << "unknown time mode argument \"" << arg << '"'; 00039 } 00040 00041 string TimeModeToString(SgTimeMode mode) 00042 { 00043 switch (mode) 00044 { 00045 case SG_TIME_CPU: 00046 return "cpu"; 00047 case SG_TIME_REAL: 00048 return "real"; 00049 default: 00050 SG_ASSERT(false); 00051 return "?"; 00052 } 00053 } 00054 00055 } // namespace 00056 00057 //---------------------------------------------------------------------------- 00058 00059 SgGtpCommands::SgGtpCommands(GtpEngine& engine, const char* programPath) 00060 : m_programPath(programPath), 00061 m_engine(engine) 00062 { 00063 } 00064 00065 SgGtpCommands::~SgGtpCommands() 00066 { 00067 } 00068 00069 void SgGtpCommands::AddGoGuiAnalyzeCommands(GtpCommand& cmd) 00070 { 00071 cmd << 00072 "param/SmartGame Param/sg_param\n"; 00073 } 00074 00075 /** Run another GTP command and compare its response against a float value. 00076 Arguments: float command [arg...] <br> 00077 Returns: -1 if response is smaller than float; 1 otherwise. 00078 */ 00079 void SgGtpCommands::CmdCompareFloat(GtpCommand& cmd) 00080 { 00081 double value = cmd.FloatArg(0); 00082 string response = m_engine.ExecuteCommand(cmd.RemainingLine(0)); 00083 istringstream in(response); 00084 double responseValue; 00085 in >> responseValue; 00086 if (! in) 00087 throw GtpFailure() << "response '" << response << "' is not a float"; 00088 cmd << (responseValue < value ? "-1" : "1"); 00089 } 00090 00091 /** Run another GTP command and compare its response against an integer value. 00092 Arguments: int command [arg...] <br> 00093 Returns: -1 if response is smaller than int; 0 if it is equal; 1 if it is 00094 greater 00095 */ 00096 void SgGtpCommands::CmdCompareInt(GtpCommand& cmd) 00097 { 00098 int value = cmd.IntArg(0); 00099 string response = m_engine.ExecuteCommand(cmd.RemainingLine(0)); 00100 istringstream in(response); 00101 int responseValue; 00102 in >> responseValue; 00103 if (! in) 00104 throw GtpFailure() << "response '" << response 00105 << "' is not an integer"; 00106 if (responseValue == value) 00107 cmd << "0"; 00108 else if (responseValue < value) 00109 cmd << "-1"; 00110 else 00111 cmd << "1"; 00112 } 00113 00114 /** Return process time. 00115 An optional string argument can be used as an ID for a timer. 00116 Default ID is "total". 00117 Other IDs are only allowed if cputime_reset was called with this ID 00118 before. 00119 */ 00120 void SgGtpCommands::CmdCpuTime(GtpCommand& cmd) 00121 { 00122 00123 string id = ParseCpuTimeId(cmd); 00124 double timeNow = SgTime::Get(SG_TIME_CPU); 00125 double timeDiff = timeNow; 00126 if (m_cpuTimes.find(id) == m_cpuTimes.end()) 00127 { 00128 if (id != "total") 00129 throw GtpFailure() << "unknown cputime id " << id; 00130 } 00131 else 00132 timeDiff -= m_cpuTimes[id]; 00133 cmd << fixed << setprecision(3) << timeDiff; 00134 } 00135 00136 /** Reset process time. 00137 An optional string argument can be used as an ID for a timer. 00138 Default ID is "total". 00139 */ 00140 void SgGtpCommands::CmdCpuTimeReset(GtpCommand& cmd) 00141 { 00142 string id = ParseCpuTimeId(cmd); 00143 double timeNow = SgTime::Get(SG_TIME_CPU); 00144 m_cpuTimes[id] = timeNow; 00145 } 00146 00147 /** Run a debugger and attach it to the current program. 00148 Arguments: debugger-type <br> 00149 Currently implemented debugger types: 00150 - gdb_kde GDB in KDE terminal 00151 - gdb_gnome GDB in GNOME terminal 00152 */ 00153 void SgGtpCommands::CmdDebugger(GtpCommand& cmd) 00154 { 00155 cmd.CheckNuArg(1); 00156 string type = cmd.Arg(0); 00157 const char* path = m_programPath; 00158 if (path == 0) 00159 throw GtpFailure("location of executable unknown"); 00160 pid_t pid = getpid(); 00161 ostringstream s; 00162 if (type == "gdb_kde") 00163 s << "konsole -e gdb " << path << ' ' << pid << " &"; 00164 else if (type == "gdb_gnome") 00165 s << "gnome-terminal -e 'gdb " << path << ' ' << pid << "' &"; 00166 else 00167 throw GtpFailure() << "unknown debugger: " << type; 00168 SgDebug() << "Executing: " << s.str() << '\n'; 00169 int retval = system(s.str().c_str()); 00170 if (retval != 0) 00171 throw GtpFailure() << "command returned " << retval; 00172 } 00173 00174 /** Echo command argument line as response. 00175 This command is compatible with GNU Go's 'echo' command. 00176 */ 00177 void SgGtpCommands::CmdEcho(GtpCommand& cmd) 00178 { 00179 cmd << cmd.ArgLine(); 00180 } 00181 00182 /** Echo command argument line to std::cerr. 00183 This command is compatible with GNU Go's 'echo_err' command. 00184 */ 00185 void SgGtpCommands::CmdEchoErr(GtpCommand& cmd) 00186 { 00187 string line = cmd.ArgLine(); 00188 cerr << line << endl; 00189 cmd << line; 00190 } 00191 00192 /** Execute GTP commands from a file. 00193 Argument: filename <br> 00194 Aborts on the first command that fails. Responses to the commands in the 00195 file are written to SgDebug() 00196 @see GtpEngine::ExecuteFile 00197 */ 00198 void SgGtpCommands::CmdExec(GtpCommand& cmd) 00199 { 00200 cmd.CheckNuArg(1); 00201 m_engine.ExecuteFile(cmd.Arg(0), SgDebug()); 00202 } 00203 00204 /** Return the current random seed. 00205 See SgRandom::SetSeed(int) for the special meaning of zero and negative 00206 values. 00207 */ 00208 void SgGtpCommands::CmdGetRandomSeed(GtpCommand& cmd) 00209 { 00210 cmd.CheckArgNone(); 00211 cmd << SgRandom::Seed(); 00212 } 00213 00214 /** Set global parameters used in module SmartGame. 00215 Parameters: 00216 @arg @c time_mode cpu|real See SgTime 00217 */ 00218 void SgGtpCommands::CmdParam(GtpCommand& cmd) 00219 { 00220 cmd.CheckNuArgLessEqual(2); 00221 if (cmd.NuArg() == 0) 00222 { 00223 // Boolean parameters first for better layout of GoGui parameter 00224 // dialog, alphabetically otherwise 00225 cmd << "[list/cpu/real] time_mode " 00226 << TimeModeToString(SgTime::DefaultMode()) << '\n'; 00227 } 00228 else if (cmd.NuArg() >= 1 && cmd.NuArg() <= 2) 00229 { 00230 string name = cmd.Arg(0); 00231 if (name == "time_mode") 00232 SgTime::SetDefaultMode(TimeModeArg(cmd, 1)); 00233 else 00234 throw GtpFailure() << "unknown parameter: " << name; 00235 } 00236 else 00237 throw GtpFailure() << "need 0 or 2 arguments"; 00238 } 00239 00240 /** Return the process ID. */ 00241 void SgGtpCommands::CmdPid(GtpCommand& cmd) 00242 { 00243 cmd.CheckArgNone(); 00244 cmd << getpid(); 00245 } 00246 00247 /** Set and store random seed. 00248 Arguments: seed <br> 00249 See SgRandom::SetSeed(int) for the special meaning of zero and negative 00250 values. 00251 */ 00252 void SgGtpCommands::CmdSetRandomSeed(GtpCommand& cmd) 00253 { 00254 cmd.CheckNuArg(1); 00255 SgRandom::SetSeed(cmd.IntArg(0)); 00256 } 00257 00258 /** Switch debug logging on/off. */ 00259 void SgGtpCommands::CmdQuiet(GtpCommand& cmd) 00260 { 00261 if (cmd.BoolArg(0)) 00262 SgDebugToNull(); 00263 else 00264 SgSwapDebugStr(&cerr); 00265 } 00266 00267 void SgGtpCommands::Register(GtpEngine& engine) 00268 { 00269 engine.Register("cputime", &SgGtpCommands::CmdCpuTime, this); 00270 engine.Register("cputime_reset", &SgGtpCommands::CmdCpuTimeReset, this); 00271 engine.Register("echo", &SgGtpCommands::CmdEcho, this); 00272 engine.Register("echo_err", &SgGtpCommands::CmdEchoErr, this); 00273 engine.Register("get_random_seed", &SgGtpCommands::CmdGetRandomSeed, this); 00274 engine.Register("pid", &SgGtpCommands::CmdPid, this); 00275 engine.Register("set_random_seed", &SgGtpCommands::CmdSetRandomSeed, this); 00276 engine.Register("sg_debugger", &SgGtpCommands::CmdDebugger, this); 00277 engine.Register("sg_compare_float", &SgGtpCommands::CmdCompareFloat, this); 00278 engine.Register("sg_compare_int", &SgGtpCommands::CmdCompareInt, this); 00279 engine.Register("sg_exec", &SgGtpCommands::CmdExec, this); 00280 engine.Register("sg_param", &SgGtpCommands::CmdParam, this); 00281 engine.Register("quiet", &SgGtpCommands::CmdQuiet, this); 00282 } 00283 00284 //---------------------------------------------------------------------------- 00285