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