15 #include "book_make.h"
16 #include "book_merge.h"
33 #include "xboard2uci.h"
42 static const char * const Version = "1.4.70b";
43 static const char * const HelpMessage = "\
45 * polyglot [configfile] [-noini] [-ec engine] [-ed enginedirectory] [-en enginename] [-log true/false] [-lf logfile] [-pg <name>=<value>]* [-uci <name>=<value>]*\n\
46 * polyglot make-book [-pgn inputfile] [-bin outputfile] [-max-ply ply] [-min-game games] [-min-score score] [-only-white] [-only-black] [-uniform]\n\
47 * polyglot merge-book -in1 inputfile1 -in2 inputfile2 [-out outputfile]\n\
48 * polyglot info-book [-bin inputfile] [-exact]\n\
49 * polyglot dump-book [-bin inputfile] -color color [-out outputfile]\n\
50 * polyglot [configfile] epd-test [engineoptions] [-epd inputfile] [-min-depth depth] [-max-depth depth] [-min-time time] [-max-time time] [-depth-delta delta]\n\
51 * polyglot perft [-fen fen] [-max-depth depth]\
54 static const int SearchDepth = 63;
55 static const double SearchTime = 3600.0;
63 static void stop_search ();
69 static void arg_shift_left(char **argv, int index){
71 for(i=index; argv[i]!=NULL; i++){
78 static void parse_args(ini_t *ini, char **argv){
82 while((arg=argv[arg_index])){
83 if(my_string_equal(arg,"-ec") && argv[arg_index+1]){
84 ini_insert_ex(ini,"PolyGlot","EngineCommand",argv[arg_index+1]);
85 arg_shift_left(argv,arg_index);
86 arg_shift_left(argv,arg_index);
88 }if(my_string_equal(arg,"-ed") && argv[arg_index+1]){
89 ini_insert_ex(ini,"PolyGlot","EngineDir",argv[arg_index+1]);
90 arg_shift_left(argv,arg_index);
91 arg_shift_left(argv,arg_index);
94 if(my_string_equal(arg,"-en") && argv[arg_index+1]){
95 ini_insert_ex(ini,"PolyGlot","EngineName",argv[arg_index+1]);
96 arg_shift_left(argv,arg_index);
97 arg_shift_left(argv,arg_index);
100 if(my_string_equal(arg,"-log") &&
102 IS_BOOL(argv[arg_index+1])){
106 TO_BOOL(argv[arg_index+1])?"true":"false");
107 arg_shift_left(argv,arg_index);
108 arg_shift_left(argv,arg_index);
111 if(my_string_equal(arg,"-lf") && argv[arg_index+1]){
112 ini_insert_ex(ini,"PolyGlot","LogFile",argv[arg_index+1]);
113 arg_shift_left(argv,arg_index);
114 arg_shift_left(argv,arg_index);
117 if(my_string_equal(arg,"-wb") &&
119 IS_BOOL(argv[arg_index+1])){
120 ini_insert_ex(ini,"PolyGlot",
122 TO_BOOL(argv[arg_index+1])?"true":"false");
123 arg_shift_left(argv,arg_index);
124 arg_shift_left(argv,arg_index);
127 if((my_string_equal(arg,"-pg")||my_string_equal(arg,"-uci")) &&
130 char section[StringSize];
131 char name[StringSize];
132 char value[StringSize];
133 ret=ini_line_parse(argv[arg_index+1],section,name,value);
135 if(my_string_equal(arg,"-pg")){
136 ini_insert_ex(ini,"PolyGlot",name,value);
138 ini_insert_ex(ini,"Engine",name,value);
141 arg_shift_left(argv,arg_index);
142 arg_shift_left(argv,arg_index);
152 static void make_ini(ini_t *ini){
154 ini_insert_ex(ini,"polyglot",
156 option_get(Option,"EngineCommand"));
157 ini_insert_ex(ini,"polyglot",
159 option_get(Option,"EngineDir"));
160 option_start_iter(Option);
161 while((opt=option_next(Option))){
162 if(my_string_case_equal(opt->name,"SettingsFile")) continue;
163 if(my_string_case_equal(opt->name,"EngineCommand")) continue;
164 if(my_string_case_equal(opt->name,"EngineDir")) continue;
165 if(!my_string_equal(opt->value,opt->default_)&& !IS_BUTTON(opt->type))
167 ini_insert_ex(ini,"polyglot",opt->name,opt->value);
170 option_start_iter(Uci->option);
171 while((opt=option_next(Uci->option))){
172 if(!strncmp(opt->name,"UCI_",4) &&
173 !my_string_case_equal(opt->name,"UCI_LimitStrength") &&
174 !my_string_case_equal(opt->name,"UCI_Elo"))continue;
175 if(!my_string_equal(opt->value,opt->default_)&&
176 !IS_BUTTON(opt->type)){
177 ini_insert_ex(ini,"engine",opt->name,opt->value);
185 static void write_ini(const char *filename,
187 // TODO Quote, dequote
190 char tmp[StringSize];
191 char tmp1[StringSize];
192 char tmp2[StringSize];
195 f=fopen(filename,"w");
197 gui_send(GUI,"tellusererror write_ini(): %s: %s.",filename,strerror(errno));
198 my_log("POLYGLOT write_ini(): %s: %s.\n",filename,strerror(errno));
201 fprintf(f,"; Created: %s\n",ctime(&t));
202 fprintf(f,"[PolyGlot]\n");
204 while((entry=ini_next(ini))){
205 if(my_string_case_equal(entry->section,"polyglot")){
206 my_quote(tmp1,entry->name,ini_specials);
207 my_quote(tmp2,entry->value,ini_specials);
208 snprintf(tmp,sizeof(tmp),"%s=%s\n",
211 tmp[sizeof(tmp)-1]='\0';
215 fprintf(f,"[Engine]\n");
217 while((entry=ini_next(ini))){
218 if(my_string_case_equal(entry->section,"engine")){
219 my_quote(tmp1,entry->name,ini_specials);
220 my_quote(tmp2,entry->value,ini_specials);
221 snprintf(tmp,sizeof(tmp),"%s=%s\n",
224 tmp[sizeof(tmp)-1]='\0';
233 void welcome_message(char *buf){
236 "PolyGlot %s by Fabien Letouzey.\n",
240 "PolyGlot %s by Fabien Letouzey (debug build).\n",
247 option_start_iter(Option);
248 while((opt=option_next(Option))){
250 if(opt->mode & XBSEL){
258 int main(int argc, char * argv[]) {
259 ini_t ini[1], ini_command[1];
265 char welcome[StringSize];
268 welcome_message(welcome);
270 printf("%s",welcome);
273 if(argc>=2 && ((my_string_case_equal(argv[1],"help")) || (my_string_case_equal(argv[1],"-help")) || (my_string_case_equal(argv[1],"--help")) || (my_string_case_equal(argv[1],"-h")) || my_string_case_equal(argv[1],"/?"))){
274 printf("%s\n",HelpMessage);
296 ini_init(ini_command);
298 // book utilities: do not touch these
300 if (argc >= 2 && my_string_equal(argv[1],"make-book")) {
301 book_make(argc,argv);
305 if (argc >= 2 && my_string_equal(argv[1],"merge-book")) {
306 book_merge(argc,argv);
310 if (argc >= 2 && my_string_equal(argv[1],"dump-book")) {
311 book_dump(argc,argv);
315 if (argc >= 2 && my_string_equal(argv[1],"info-book")) {
316 book_info(argc,argv);
322 if (argc >= 2 && my_string_equal(argv[1],"perft")) {
327 // What is the config file? This is very hacky right now.
329 // Do we want a config file at all?
333 while((arg=argv[arg_index++])){
334 if(my_string_equal(arg,"-noini")){
339 arg_shift_left(argv,arg_index-1);
340 parse_args(ini_command,argv+1);
342 option_set(Option,"SettingsFile","<empty>");
345 // Ok see if first argument looks like config file
347 if(argv[1] && !my_string_equal(argv[1],"epd-test") && !(argv[1][0]=='-')){
348 // first argument must be config file
350 option_set(Option,"SettingsFile",argv[1]);
354 arg_shift_left(argv,1);
356 // Config file is the default.
357 // This has already been set above or in "option_init_pg()"
362 // if we use a config file: load it!
364 if(!my_string_equal(option_get_string(Option,"SettingsFile"),"<empty>")){
365 if(ini_parse(ini,option_get_string(Option,"SettingsFile"))){
366 my_fatal("main(): Can't open config file \"%s\": %s\n",
367 option_get_string(Option,"SettingsFile"),
372 // Extract some important options
374 if((entry=ini_find(ini,"polyglot","EngineCommand"))){
375 option_set(Option,entry->name,entry->value);
377 if((entry=ini_find(ini,"polyglot","EngineDir"))){
378 option_set(Option,entry->name,entry->value);
380 if((entry=ini_find(ini,"polyglot","EngineName"))){
381 option_set(Option,entry->name,entry->value);
383 if((entry=ini_find(ini,"polyglot","Log"))){
384 polyglot_set_option(entry->name,entry->value);
386 if((entry=ini_find(ini,"polyglot","LogFile"))){
387 polyglot_set_option(entry->name,entry->value);
390 // Concession to WB 4.4.0
391 // Treat "polyglot_1st.ini" and "polyglot_2nd.ini" specially
393 if(option_get_bool(Option,"WbWorkArounds3")){
394 const char *SettingsFile=option_get(Option,"SettingsFile");
395 if(strstr(SettingsFile,"polyglot_1st.ini")||
396 strstr(SettingsFile,"polyglot_2nd.ini")){
397 option_set(Option,"SettingsFile","<empty>");
401 // Look at command line for logging option. It is important
402 // to start logging as soon as possible.
404 if((entry=ini_find(ini_command,"PolyGlot","Log"))){
405 option_set(Option,entry->name,entry->value);
407 if((entry=ini_find(ini_command,"PolyGlot","LogFile"))){
408 option_set(Option,entry->name,entry->value);
411 // start logging if required
413 if (option_get_bool(Option,"Log")) {
414 my_log_open(option_get_string(Option,"LogFile"));
419 my_log("%s",welcome);
420 my_log("POLYGLOT *** START ***\n");
421 if(!my_string_equal(option_get_string(Option,"SettingsFile"),"<empty>")){
422 my_log("POLYGLOT INI file \"%s\"\n",option_get_string(Option,"SettingsFile"));
426 // scavenge command line for options necessary to start the engine
429 if((entry=ini_find(ini_command,"PolyGlot","EngineCommand"))){
430 option_set(Option,entry->name,entry->value);
432 if((entry=ini_find(ini_command,"PolyGlot","EngineDir"))){
433 option_set(Option,entry->name,entry->value);
435 if((entry=ini_find(ini_command,"PolyGlot","EngineName"))){
436 option_set(Option,entry->name,entry->value);
439 // Make sure that EngineCommand has been set
440 if(my_string_case_equal(option_get(Option,"EngineCommand"),"<empty>")){
441 my_fatal("main(): EngineCommand not set\n");
448 if(!engine_active(Engine)){
449 my_fatal("main(): Could not start \"%s\"\n",option_get(Option,"EngineCommand"));
452 // switch to UCI mode if necessary
454 if (option_get_bool(Option,"UCI")) {
455 my_log("POLYGLOT *** Switching to UCI mode ***\n");
458 // initialize uci parsing and send uci command.
459 // Parse options and wait for uciok
462 uci_open(Uci,Engine);
464 option_set_default(Option,"EngineName",Uci->name);
466 // get engine name from engine if not supplied in config file or on
469 if (my_string_equal(option_get_string(Option,"EngineName"),"<empty>")) {
470 option_set(Option,"EngineName",Uci->name);
474 // In the case we have been invoked with NoIni or StandardIni
475 // we still have to load a config file.
477 if(my_string_equal(option_get_string(Option,"SettingsFile"),"<empty>")){
479 // construct the name of the ConfigFile from the EngineName
481 char tmp[StringSize];
482 char option_file[StringSize];
484 snprintf(tmp,sizeof(tmp),"%s.ini",
485 option_get_string(Option,"EngineName"));
486 tmp[sizeof(tmp)-1]='\0';
487 for(i=0;i<strlen(tmp);i++){
492 my_path_join(option_file,
493 option_get_string(Option,"SettingsDir"),
495 // Load the config file
496 option_set(Option,"SettingsFile",option_file);
498 my_log("POLYGLOT INI file \"%s\"\n",option_get_string(Option,"SettingsFile"));
499 if(ini_parse(ini,option_file)){
500 my_log("POLYGLOT Unable to open %s\n",
501 option_get_string(Option,"SettingsFile"));
506 // Parse the command line and merge remaining options.
508 ini_start_iter(ini_command);
509 while((entry=ini_next(ini_command))){
510 ini_insert(ini,entry);
513 // Remind the reader about the options that are now in effect.
515 my_log("POLYGLOG OPTIONS \n");
518 // extract PG options
521 while((entry=ini_next(ini))){
522 if(my_string_case_equal(entry->section,"polyglot")){
523 opt=option_find(Option,entry->name);
524 if(opt && !IS_BUTTON(opt->type)){
525 polyglot_set_option(entry->name,entry->value);
530 // Cater to our biggest customer:-)
532 if(option_get_bool(Option,"OnlyWbOptions")){
540 // collect engine options from config file(s) and send to engine
543 while((entry=ini_next(ini))){
544 if(my_string_case_equal(entry->section,"engine")){
545 // also updates value in Uci->option
546 uci_send_option(Uci,entry->name,"%s",entry->value);
554 if (argv[1] && my_string_equal(argv[1],"epd-test")){
556 while((arg=argv[argc++]));
557 epd_test(argc-1,argv);
561 // Anything that hasn't been parsed yet is a syntax error
562 // It seems that XBoard sometimes passes empty strings as arguments
563 // to PolyGlot. We ignore these.
566 while((arg=argv[argc++])){
567 if(!my_string_equal(arg,"")){
568 my_fatal("main(): Incorrect use of option: \"%s\"\n",argv[argc-1]);
577 // polyglot_set_option()
579 void polyglot_set_option(const char *name, const char *value){ // this must be cleaned up!
583 my_log("POLYGLOT Setting PolyGlot option \"%s=%s\"\n",name,value);
584 if(my_string_case_equal(name,"Save")){
585 ret=my_mkdir(option_get(Option,"SettingsDir"));
587 my_log("POLYGLOT polyglot_set_option(): %s: %s\n",
588 option_get(Option,"SettingsDir"),
592 write_ini(option_get(Option,"SettingsFile"),ini);
595 // if(my_string_equal(option_get(Option,name),value)){
596 // my_log("Not setting PolyGlot option \"%s\" "
597 // "since it already as the correct value.\n",
601 option_set(Option,name,value);
602 if(option_get_bool(Option,"Book")&&(my_string_case_equal(name,"BookFile")||my_string_case_equal(name,"Book"))){
603 my_log("POLYGLOT *** SETTING BOOK ***\n");
604 my_log("POLYGLOT BOOK \"%s\"\n",option_get_string(Option,"BookFile"));
607 book_open(option_get_string(Option,"BookFile"));
609 my_log("POLYGLOT Unable to open book \"%s\"\n",option_get_string(Option,"BookFile"));
611 }else if(option_get_bool(Option,"Log")&&(my_string_case_equal(name,"LogFile") ||my_string_case_equal(name,"Log"))){
612 my_log("POLYGLOT *** SWITCHING LOGFILE ***\n");
613 my_log("POLYGLOT NEW LOGFILE \"%s\"\n",option_get_string(Option,"LogFile"));
615 my_log_open(option_get_string(Option,"LogFile"));
616 }else if(option_get_bool(Option,"UseNice") &&(my_string_case_equal(name,"NiceValue")||my_string_case_equal(name,"UseNice"))){
617 my_log("POLYGLOT Adjust Engine Piority\n");
618 engine_set_nice_value(Engine,atoi(option_get_string(Option,"NiceValue")));
619 }else if(my_string_case_equal(name,"Book") && !option_get_bool(Option,"Book")){
622 }else if(my_string_case_equal(name,"UseNice") && !option_get_bool(Option,"UseNice")){
623 my_log("POLYGLOT Adjust Engine Piority\n");
624 engine_set_nice_value(Engine,0);
625 }else if(my_string_case_equal(name,"Log") && !option_get_bool(Option,"Log")){
626 my_log("POLYGLOT QUIT LOGGING\n");
636 my_log("POLYGLOT *** QUIT ***\n");
637 if (Init && !Engine->pipex->quit_pending) {
639 Engine->pipex->quit_pending=TRUE;
640 engine_send(Engine,"quit");
641 engine_close(Engine);
645 my_log("POLYGLOT Calling exit\n");
651 static void stop_search() {
653 if (Init && Uci->searching) {
655 ASSERT(Uci->searching);
656 ASSERT(Uci->pending_nb>=1);
658 my_log("POLYGLOT STOP SEARCH\n");
660 if (option_get_bool(Option,"SyncStop")) {
661 uci_send_stop_sync(Uci);