"Fossies" - the Fresh Open Source Software Archive

Member "gnuchess-6.2.9/src/frontend/cmd.cc" (13 Jul 2021, 37093 Bytes) of package /linux/privat/gnuchess-6.2.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cmd.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.2.8_vs_6.2.9.

    1 /* cmd.cc
    2 
    3    GNU Chess frontend
    4 
    5    Copyright (C) 2001-2021 Free Software Foundation, Inc.
    6 
    7    GNU Chess is based on the two research programs
    8    Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.
    9 
   10    This program is free software: you can redistribute it and/or modify
   11    it under the terms of the GNU General Public License as published by
   12    the Free Software Foundation, either version 3 of the License, or
   13    (at your option) any later version.
   14 
   15    This program is distributed in the hope that it will be useful,
   16    but WITHOUT ANY WARRANTY; without even the implied warranty of
   17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18    GNU General Public License for more details.
   19 
   20    You should have received a copy of the GNU General Public License
   21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   22 
   23    Contact Info:
   24      bug-gnu-chess@gnu.org
   25      cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
   26 */
   27 
   28 #include <stdio.h>
   29 #include <stdlib.h>
   30 #include <string.h>
   31 #include <unistd.h>
   32 #include <ctype.h>
   33 #include <errno.h>
   34 
   35 #include "version.h"
   36 #include "common.h"
   37 #include "gettext.h"
   38 
   39 #define _(str) gettext (str)
   40 
   41 static char logfile[MAXSTR];
   42 static char gamefile[MAXSTR];
   43 
   44 /*
   45  * Splitting input is actually not neccessary, but we find
   46  * tokens separated by whitespace and put pointers on them.
   47  * How many do we need? We just take 3 for now. Check if the
   48  * fact that tokens are not 0-terminated but whitespace-terminated
   49  * generates bugs. (Already killed one bug in move.c)
   50  * We also kill trailing whitespace. (The trailing '\n' might
   51  * be really annoying otherwise.)
   52  */
   53 
   54 #define TOKENS 3
   55 
   56 static char *token[TOKENS];
   57 char *endptr;
   58 
   59 static int hardFlag=0;
   60 static int postFlag=0;
   61 
   62 static const char setboard_cmd[] = "setboard ";
   63 
   64 static void split_input(void)
   65 {
   66   /* r points to the last non-space character */
   67   char *s, *r;
   68   int k;
   69 
   70   for (k = 0, s = r = inputstr; k < TOKENS; ++k) {
   71     /* Skip leading whitespace */
   72     while (isspace(*s)) s++;
   73     token[k] = s;
   74     /* Skip token */
   75     while (*s && !isspace(*s)) r = s++;
   76   }
   77   while (*s) {
   78     while (isspace(*s)) s++;
   79     while (*s && !isspace(*s)) r = s++;
   80   }
   81   r[1] = '\0';
   82 }
   83 
   84 /*
   85  * Compares two tokens, returns 1 on equality. Tokens
   86  * are separated by whitespace.
   87  */
   88 static int tokeneq(const char *s, const char *t)
   89 {
   90   while (*s && *t && !isspace(*s) && !isspace(*t)) {
   91     if (*s++ != *t++) return 0;
   92   }
   93   return (!*s || isspace(*s)) && (!*t || isspace(*t));
   94 }
   95 
   96 /*
   97  * Remove a trailing \n and return NULL if last character is not \n.
   98  */
   99 static char *trim_newline(char *line)
  100 {
  101   if (line == NULL) {
  102     return NULL;
  103   }
  104   const size_t line_len = strlen(line);
  105   const size_t last_char_index = strlen(line) - 1;
  106   if (line_len <= 0 || line[last_char_index] != '\n') {
  107     return NULL;
  108   }
  109   line[last_char_index] = '\0';
  110   return line;
  111 }
  112 
  113 /*
  114  * Takes an EPD filename as input and returns the contents as a
  115  * 'setboard <epd-position>' command.
  116  */
  117 static char *build_setboard_cmd_from_epd_file(char *data, const char *epd_filename, unsigned int data_len)
  118 {
  119   char *result = NULL;
  120   char *epdline = (char *)calloc(data_len, sizeof(char));
  121 
  122   if (epdline == NULL) {
  123     return NULL;
  124   }
  125   FILE *epdfile = fopen(epd_filename, "r");
  126   if (epdfile == NULL) {
  127     return NULL;
  128   }
  129   if (fgets(epdline, data_len, epdfile) && trim_newline(epdline) && strlen(setboard_cmd) + strlen(epdline) < data_len) {
  130     strcpy(data, setboard_cmd);
  131     strcat(data, epdline);
  132     result = data;
  133   }
  134   fclose(epdfile);
  135   free(epdline);
  136 
  137   return result;
  138 }
  139 
  140 /*
  141  * Takes a PGN filename as input and returns the contents as a
  142  * 'setboard <epd-position>' command.
  143  */
  144 static char *build_setboard_cmd_from_pgn_file(char *data, const char *pgn_filename, unsigned int data_len)
  145 {
  146   char *result = NULL;
  147   char *epdline = (char *)calloc(data_len, sizeof(char));
  148 
  149   if (epdline == NULL) {
  150     return NULL;
  151   }
  152   PGNReadFromFile (pgn_filename, 0);
  153   EPD2str(epdline);
  154   if (strlen(setboard_cmd) + strlen(epdline) < data_len) {
  155     strcpy(data, setboard_cmd);
  156     strcat(data, epdline);
  157     result = data;
  158   }
  159   free(epdline);
  160 
  161   return result;
  162 }
  163 
  164 /*
  165  * Loads a PGN file. Returns 1 on success, 0 on error.
  166  */
  167 static int pgnload(const char *pgn_filename)
  168 {
  169   int success;
  170   char data[MAXSTR]="";
  171 
  172   if (build_setboard_cmd_from_pgn_file(data, pgn_filename, sizeof(data))) {
  173     SetDataToEngine( data );
  174     SetAutoGo( true );
  175     success = 1;
  176   } else {
  177     printf( _("Error loading PGN file '%s'.\n"), pgn_filename );
  178     success = 0;
  179   }
  180   return success;
  181 }
  182 
  183 void cmd_accepted(void)
  184 {
  185   SetDataToEngine( token[0] );
  186 }
  187 
  188 void cmd_activate(void)
  189 {
  190   printf( _("Command 'activate' is currently not supported.\n") );
  191 }
  192 
  193 void cmd_analyze(void)
  194 {
  195   /*
  196    * "analyze" mode is similar to force, hard and post together
  197    * in that it produces a text output like post, but must
  198    * think indefinitely like ponder.
  199    *
  200    * Some additional output is expected in command ".\n" but if ignored
  201    * this should not be sent any more
  202    */
  203 
  204 /* TODO correct output, add fail high low */
  205 
  206   SET (flags, ANALYZE);
  207   SetDataToEngine( "hard\npost\nanalyze" );
  208 }
  209 
  210 void cmd_bk(void)
  211 {
  212   SetDataToEngine( "bk" );
  213 }
  214 
  215 void cmd_black(void)
  216 {
  217  /*
  218   * No longer used by Xboard but requested as a feature
  219   */
  220   printf( _("Command 'black' is currently not supported.\n") );
  221 }
  222 
  223 void cmd_book(void)
  224 {
  225   char data[MAXSTR]="";
  226   strcpy( data, "book " );
  227   if (tokeneq(token[1], "add")) {
  228     if (access(token[2], F_OK) < 0) {
  229       printf(_("The syntax to add a new book is:\n\n\tbook add file.pgn\n"));
  230     } else {
  231       strcat( data, "add " );
  232       strcat( data, token[2] );
  233     }
  234   } else if (tokeneq (token[1], "on") || tokeneq(token[1], "prefer")) {
  235     strcpy( data, "book on" );
  236     printf(_("Book is now on.\n"));
  237   } else if (tokeneq (token[1], "off")) {
  238     strcpy( data, "book off" );
  239     printf(_("Book is now off.\n"));
  240   } else if (tokeneq (token[1], "best")) {
  241     strcpy( data, "book best" );
  242     printf(_("Book is now best.\n"));
  243   } else if (tokeneq (token[1], "worst")) {
  244     strcpy( data, "book worst" );
  245     printf(_("Book is now worst.\n"));
  246   } else if (tokeneq (token[1], "random")) {
  247     strcpy( data, "book random" );
  248     printf(_("Book is now random.\n"));
  249   } else {
  250     printf( _("Incorrect book option: '%s'.\n"), token[1] );
  251     return;
  252   }
  253   SetDataToEngine( data );
  254 }
  255 
  256 void cmd_depth(void)
  257 {
  258   char data[MAXSTR]="";
  259   int searchDepth=0;
  260   searchDepth = atoi( token[1] );
  261   sprintf( data, "sd %d", searchDepth );
  262   SetDataToEngine( data );
  263   printf(_("Search to a depth of %d.\n"),searchDepth);
  264 }
  265 
  266 void cmd_easy(void)
  267 {
  268   SetDataToEngine( token[0] );
  269 }
  270 
  271 /* Predecessor to setboard */
  272 void cmd_edit(void)
  273 {
  274   if ( flags & XBOARD ) {
  275     printf("tellusererror command 'edit' not implemented\n");
  276     fflush(stdout);
  277   }
  278 }
  279 
  280 void cmd_exit(void)
  281 {
  282   /*
  283    * "exit" is a synonym for quit except in engine mode
  284    * when it means leave analyze mode
  285    */
  286 
  287   if ( flags & ANALYZE ){
  288     flags = preanalyze_flags ; /* this implicitly clears ANALYZE flag */
  289     SetDataToEngine( token[0] );
  290   } else {
  291     cmd_quit();
  292   }
  293 }
  294 
  295 void cmd_force(void)
  296 {
  297   SET (flags, MANUAL);
  298   SetDataToEngine( token[0] );
  299 }
  300 
  301 void cmd_go(void)
  302 {
  303   SET (flags, THINK);
  304   CLEAR (flags, MANUAL);
  305   CLEAR (flags, TIMEOUT);
  306   CLEAR (flags, ENDED);
  307   computer = board.side;
  308   ExpectAnswerFromEngine( true );
  309   ChangeColor( true );
  310   SetDataToEngine( token[0] );
  311   pgnloaded = 0;
  312 }
  313 
  314 void cmd_hard(void)
  315 {
  316   SetDataToEngine( token[0] );
  317 }
  318 
  319 void cmd_hash(void)
  320 {
  321   if (tokeneq (token[1], "off")) {
  322     CLEAR (flags, USEHASH);
  323     SetDataToEngine( "hashoff" );
  324   } else if (tokeneq (token[1], "on")) {
  325     SET (flags, USEHASH);
  326     SetDataToEngine( "hashon" );
  327   }
  328   if ( flags & USEHASH ) {
  329     printf( _("Hashing is on.\n") );
  330   } else {
  331     printf( _("Hashing is off.\n") );
  332   }
  333 }
  334 
  335 /* Give a possible move for the player to play */
  336 void cmd_hint(void)
  337 {
  338   /* An answer is received only if book on - TODO change this in adapter */
  339   SetDataToEngine( token[0] );
  340   /* TODO if no hint, inform on stdout */
  341 }
  342 
  343 void cmd_ics(void)
  344 {
  345   SetDataToEngine( token[0] );
  346 }
  347 
  348 void cmd_level(void)
  349 {
  350   SetDataToEngine( token[0] );
  351   sscanf (token[1], "%d %f %d", &TCMove, &TCTime, &TCinc);
  352   if (TCMove == 0) {
  353     TCMove =  35 /* MIN((5*(GameCnt+1)/2)+1,60) */;
  354     printf("TCMove = %d\n",TCMove);
  355   }
  356   if (TCTime == 0) {
  357     SearchTime = TCinc / 2.0f ;
  358     printf(_("Fischer increment of %d seconds.\n"),TCinc);
  359   } else {
  360     MoveLimit[white] = MoveLimit[black] = TCMove - (GameCnt+1)/2;
  361     TimeLimit[white] = TimeLimit[black] = TCTime * 60;
  362     if (!(flags & XBOARD)) {
  363       /* TRANSLATORS: Please be aware that the word 'move' is sometimes
  364          used as a synonym of 'ply', and sometimes in the sense of a
  365          full 2-ply move. */
  366       printf (_("Time control: %d moves in %.2f secs.\n"),
  367       MoveLimit[white], TimeLimit[white]);
  368       printf(_("Fischer increment of %d seconds.\n"),TCinc);
  369     }
  370   }
  371 }
  372 
  373 void cmd_list(void)
  374 {
  375   if (token[1][0] == '?') {
  376     printf(_("name    - list known players alphabetically\n"));
  377     printf(_("score   - list by GNU best result first\n"));
  378     printf(_("reverse - list by GNU worst result first\n"));
  379   } else {
  380     if (token[1][0] == '\0') DBListPlayer("rscore");
  381     else DBListPlayer(token[1]);
  382   }
  383 }
  384 
  385 void cmd_load(void)
  386 {
  387   char *epd_filename = token[1];
  388   char data[MAXSTR]="";
  389   LoadEPD (epd_filename);
  390   pgnloaded = 0;
  391   check_board();
  392   if (!ValidateBoard()) {
  393     SET (flags, ENDED);
  394     printf (_("Board is wrong!\n"));
  395   } else {
  396     /* Read EPD file and send contents to engine */
  397     if (build_setboard_cmd_from_epd_file(data, epd_filename, strlen(data))) {
  398       SetDataToEngine( data );
  399       SetAutoGo( true );
  400     } else {
  401       printf( _("Error loading EPD file '%s'.\n"), epd_filename );
  402     }
  403   }
  404 }
  405 
  406 void cmd_manual(void)
  407 {
  408   SET (flags, MANUAL);
  409   ExpectAnswerFromEngine( false );
  410   SetDataToEngine( "force" );
  411 }
  412 
  413 void cmd_memory(void)
  414 {
  415   if (token[1][0] == 0) {
  416     ExpectAnswerFromEngine( true );
  417     SetDataToEngine( "memory" );
  418   } else {
  419     unsigned int memory;
  420     if ( sscanf( token[1], "%d", &memory ) == 1 ) {
  421       char data[MAXSTR]="";
  422       sprintf( data, "memory %d\nmemory", memory );
  423       SetDataToEngine( data );
  424     }
  425 /* TODO Handle error */
  426   }
  427 }
  428 
  429 /* Move now, not applicable */
  430 void cmd_movenow(void)
  431 {
  432   SetDataToEngine( "?" );
  433 }
  434 
  435 /*
  436  * TODO: Add a logpath variable or macro, not always dump into current
  437  * dir. Again, how does one handle paths portably across Unix/Windows?
  438  *   -- Lukas
  439  */
  440 void cmd_name(void)
  441 {
  442   SetDataToEngine( token[0] );
  443   int suffix = 0;
  444 
  445   /* name[sizeof name - 1] should always be 0 */
  446   strncpy(name, token[1], sizeof name - 1);
  447   for (suffix = 0; suffix < 1000; suffix++) {
  448     sprintf(logfile,"log.%03d",suffix);
  449     sprintf(gamefile,"game.%03d",suffix);
  450     /*
  451      * There is an obvious race condition here but who cares, we just
  452      * bail out in case of failure... --Lukas
  453      */
  454     if (access(logfile,F_OK) < 0) {
  455       ofp = fopen(logfile,"w");
  456       if (ofp == NULL) {
  457         ofp = stdout;
  458         fprintf(stderr, _("Failed to open %s for writing: %s\n"),
  459         logfile, strerror(errno));
  460       }
  461       return;
  462     }
  463   }
  464   fprintf(stderr, _("Could not create logfile, all slots occupied.\n"));
  465   fprintf(stderr, _("You may consider deleting or renaming your existing logfiles.\n"));
  466 }
  467 
  468 void cmd_new(void)
  469 {
  470   InitVars ();
  471   NewPosition ();
  472   /* Protocol specification for ANALYZE says "new" does not end analysis */
  473   if (!(flags & ANALYZE))
  474     CLEAR (flags, MANUAL);
  475   CLEAR (flags, THINK);
  476   myrating = opprating = 0;
  477   SetDataToEngine( token[0] );
  478 }
  479 
  480 void cmd_nopost(void)
  481 {
  482   CLEAR (flags, POST);
  483   postFlag = 0;
  484   ExpectAnswerFromEngine( false );
  485   SetDataToEngine( token[0] );
  486 }
  487 
  488 void cmd_null(void)
  489 {
  490   if (tokeneq (token[1], "off")) {
  491     CLEAR (flags, USENULL);
  492     SetDataToEngine( "nulloff" );
  493   } else if (tokeneq (token[1], "on")) {
  494     SET (flags, USENULL);
  495     SetDataToEngine( "nullon" );
  496   }
  497   if ( flags & USENULL ) {
  498     printf( _("Null-move heuristic is on.\n") );
  499   } else {
  500     printf( _("Null-move heuristic is off.\n") );
  501   }
  502 }
  503 
  504 void cmd_otim(void)
  505 {
  506    SetDataToEngine( token[0] );
  507 }
  508 
  509 /*
  510  * Load a file containing a game in PGN format.
  511  *
  512  * The file contents will be passed on to the adapter
  513  * in EPD notation (the adapter expectes FEN actually,
  514  * but EPD and FEN are similar (possible issue here?),
  515  * hence a PGN -> EPD conversion in done first.
  516  */
  517 void cmd_pgnload(void)
  518 {
  519   pgnload(token[1]);
  520 }
  521 
  522 /* See comment above in cmd_pgnload about PGN -> EPD conversion. */
  523 void cmd_pgnreplay(void)
  524 {
  525   if (!pgnload(token[1])) {
  526     return;
  527   }
  528   pgnloaded = 1;
  529   pgncnt = GameCnt;
  530 
  531   while (GameCnt >= 0) {
  532     if (GameCnt >= 0) {
  533       CLEAR (flags, ENDED);
  534       CLEAR (flags, TIMEOUT);
  535       ChangeColor( true );
  536       SetAutoGo( true );
  537       UnmakeMove (board.side, &Game[GameCnt].move);
  538       if (GameCnt >= 0) {
  539         UnmakeMove (board.side, &Game[GameCnt].move);
  540       }
  541     }
  542   }
  543 
  544   cmd_first();
  545 }
  546 
  547 void cmd_next(void)
  548 {
  549   if (!pgnloaded) {
  550     printf(_("Error: PGN file not loaded!\n"));
  551     return;
  552   }
  553 
  554   if ((GameCnt+1) <= pgncnt) {
  555     ChangeColor( true );
  556     SetAutoGo( true );
  557     MakeMove (board.side, &Game[GameCnt+1].move);
  558   } else {
  559     printf(_("No more moves. Game reached the end.\n"));
  560     return;
  561   }
  562 
  563   printf("%d. ",GameCnt/2+1);
  564   printf("%s\n", Game[GameCnt].SANmv);
  565   ShowBoard ();
  566 }
  567 
  568 void cmd_previous(void)
  569 {
  570   if (!pgnloaded) {
  571     printf(_("Error: PGN file not loaded!\n"));
  572     return;
  573   }
  574 
  575   if (GameCnt >= 0) {
  576     ChangeColor( true );
  577     SetAutoGo( true );
  578     UnmakeMove (board.side, &Game[GameCnt].move);
  579   }
  580   else {
  581     printf(_("Initial position reached. There are no earlier moves.\n"));
  582     return;
  583   }
  584 
  585   printf("%d. ",GameCnt/2+1);
  586   printf("%s\n", Game[GameCnt].SANmv);
  587   ShowBoard ();
  588 }
  589 
  590 void cmd_last(void)
  591 {
  592   if (!pgnloaded) {
  593     printf(_("Error: PGN file not loaded!\n"));
  594     return;
  595   }
  596 
  597   while (GameCnt+1 <= pgncnt) {
  598     ChangeColor( true );
  599     SetAutoGo( true );
  600     MakeMove (board.side, &Game[GameCnt+1].move);
  601   }
  602 
  603   printf("%d. ",GameCnt/2+1);
  604   printf("%s\n", Game[GameCnt].SANmv);
  605   ShowBoard ();
  606 }
  607 
  608 void cmd_first(void)
  609 {
  610   if (!pgnloaded) {
  611     printf(_("Error: PGN file not loaded!\n"));
  612     return;
  613   }
  614 
  615   while (GameCnt >= 0) {
  616     if (GameCnt >= 0) {
  617       CLEAR (flags, ENDED);
  618       CLEAR (flags, TIMEOUT);
  619       ChangeColor( true );
  620       SetAutoGo( true );
  621       UnmakeMove (board.side, &Game[GameCnt].move);
  622       if (GameCnt >= 0) {
  623         UnmakeMove (board.side, &Game[GameCnt].move);
  624       }
  625     }
  626   }
  627 
  628   ShowBoard ();
  629 }
  630 
  631 /*
  632  * XXX - Filenames with spaces will break here,
  633  * do we want to support them? I vote for "no"
  634  *   - Lukas
  635  */
  636 void cmd_pgnsave(void)
  637 {
  638   if ( strlen(token[1]) > 0 )
  639     PGNSaveToFile (token[1], "");
  640   else
  641     printf(_("Invalid filename.\n"));
  642 }
  643 
  644 void cmd_graphic(void)
  645 {
  646   graphicmodeoutput = 1;
  647   printf(_("Graphic mode is enabled.\n"));
  648 }
  649 
  650 void cmd_nographic(void)
  651 {
  652   graphicmodeoutput = 0;
  653   printf(_("Graphic mode is disabled.\n"));
  654 }
  655 
  656 void cmd_ping(void)
  657 {
  658   /* TODO cf. 5.08 */
  659   SetDataToEngine( token[0] );
  660   /* If ping is received when we are on move, we are supposed to
  661      reply only after moving.  In this version of GNU Chess, we
  662      never read commands while we are on move, so we don't have to
  663      worry about that here. */
  664   printf("pong %s\n", token[1]);
  665   fflush(stdout);
  666 }
  667 
  668 void cmd_post(void)
  669 {
  670   /* TODO State makes no sense */
  671   SET (flags, POST);
  672   postFlag = 1;
  673   if ( hardFlag && postFlag )
  674     ExpectAnswerFromEngine( true );
  675   if ( flags & XBOARD )
  676     ExpectAnswerFromEngine( true );
  677   else
  678     ExpectAnswerFromEngine( false );
  679   SetDataToEngine( token[0] );
  680 }
  681 
  682 void cmd_protover(void)
  683 {
  684   SetDataToEngine( token[0] );
  685   return;
  686   if (flags & XBOARD) {
  687     /* Note: change this if "draw" command is added, etc. */
  688     printf("feature setboard=1 analyze=1 ping=1 draw=0 sigint=0\
  689  variants=\"normal\" myname=\"%s %s\" done=1\n",
  690       PROGRAM, VERSION);
  691     fflush(stdout);
  692   }
  693 }
  694 
  695 void cmd_quit(void) { SET (flags, QUIT); }
  696 
  697 void cmd_random(void)
  698 {
  699   printf( _("Command 'random' is currently not supported.\n") );
  700   //SetDataToEngine( token[0] );
  701 }
  702 
  703 void cmd_rating(void)
  704 {
  705   myrating = atoi(token[1]);
  706   opprating = atoi(token[2]);
  707   fprintf(ofp,_("my rating = %d, opponent rating = %d\n"),myrating,opprating);
  708   /* Change randomness of book based on opponent rating. */
  709   /* Basically we play narrower book the higher the opponent */
  710   if (opprating >= 1700) bookfirstlast = 2;
  711   else if (opprating >= 1700) bookfirstlast = 2;
  712   else bookfirstlast = 2;
  713 }
  714 
  715 void cmd_rejected(void) {}
  716 
  717 void cmd_remove(void)
  718 {
  719   SetDataToEngine( token[0] );
  720   if (GameCnt >= 0) {
  721     CLEAR (flags, ENDED);
  722     CLEAR (flags, TIMEOUT);
  723     UnmakeMove (board.side, &Game[GameCnt].move);
  724     if (GameCnt >= 0) {
  725       UnmakeMove (board.side, &Game[GameCnt].move);
  726       if (!(flags & XBOARD))
  727            ShowBoard ();
  728     }
  729     PGNSaveToFile ("game.log","");
  730   } else
  731     printf (_("No moves to undo!\n"));
  732 }
  733 
  734 void cmd_result(void)
  735 {
  736   /* TODO Do not send to engine */
  737   SetDataToEngine( token[0] );
  738   if (ofp != stdout) {
  739     fprintf(ofp, "result: %s\n",token[1]);
  740     fclose(ofp);
  741     ofp = stdout;
  742     printf(_("Save to %s\n"),gamefile);
  743     PGNSaveToFile (gamefile, token[1]);
  744     DBUpdatePlayer (name, token[1]);
  745   }
  746 }
  747 
  748 void cmd_save(void)
  749 {
  750   if ( strlen(token[1]) > 0 )
  751     SaveEPD (token[1]);
  752   else
  753     printf(_("Invalid filename.\n"));
  754 }
  755 
  756 void cmd_setboard(void)
  757 {
  758   /* setboard uses FEN, not EPD, but ParseEPD will accept FEN too */
  759   char data[MAXSTR]="";
  760   ParseEPD (token[1]);
  761   NewPosition();
  762   check_board();
  763   snprintf(data, sizeof(data), "setboard %s", token[1]);
  764   SetDataToEngine(data);
  765 }
  766 
  767 void cmd_solve(void)
  768 {
  769   Solve (token[1]);
  770 }
  771 
  772 /* Set total time for move to be N seconds is "st N" */
  773 void cmd_st(void)
  774 {
  775   char data[MAXSTR]="";
  776   /* Approximately level 1 0 N */
  777   sscanf(token[1],"%d",&TCinc);
  778   /* Allow a little fussiness for failing low etc */
  779   SearchTime = TCinc * 0.90f ;
  780   sprintf( data, "st %d", atoi( token[1] ) );
  781   SetDataToEngine( data );
  782 }
  783 
  784 void cmd_switch(void)
  785 {
  786   printf( _("Command 'switch' is currently not supported.\n") );
  787 }
  788 
  789 void cmd_time(void)
  790 {
  791   /* TODO send what? */
  792   SetDataToEngine( token[0] );
  793   TimeLimit[1^board.side] = atoi(token[1]) / 100.0f ;
  794 }
  795 
  796 void cmd_undo(void)
  797 {
  798   SetDataToEngine( "force\nundo" );
  799   ChangeColor( true );
  800   SetAutoGo( !(flags & MANUAL) );
  801   if (GameCnt >= 0)
  802     UnmakeMove (board.side, &Game[GameCnt].move);
  803   else
  804     printf (_("No moves to undo!\n"));
  805   MoveLimit[board.side]++;
  806   TimeLimit[board.side] += Game[GameCnt+1].et;
  807   if (!(flags & XBOARD)) ShowBoard ();
  808 }
  809 
  810 void cmd_usage(void)
  811 {
  812       printf ( "\n" );
  813       printf ( _("\
  814 Usage: %s [OPTION]...\n\n"), progname );
  815       fputs( _("\
  816 Play the game of chess.\n\n"), stdout );
  817       fputs( _("Options:\n"), stdout );
  818       fputs( _("\
  819  -h, --help         display this help and exit\n"), stdout );
  820       fputs( _("\
  821  -v, --version      display version information and exit\n"), stdout );
  822       fputs( _("\
  823  -q, --quiet        make the program silent on startup\n"), stdout );
  824       fputs( _("\
  825      --silent       same as -q\n"), stdout );
  826       fputs( _("\
  827 \n"), stdout );
  828       fputs( _("\
  829  -x, --xboard       start in engine mode\n"), stdout );
  830       fputs( _("\
  831  -p, --post         start up showing thinking\n"), stdout );
  832       fputs( _("\
  833  -e, --easy         disable thinking in opponents time\n"), stdout );
  834       fputs( _("\
  835  -m, --manual       enable manual mode\n"), stdout );
  836       fputs( _("\
  837  -u, --uci          enable UCI protocol (externally behave as UCI engine)\n"), stdout );
  838       fputs( _("\
  839  -M size, --memory=size   specify memory usage in MB for hashtable\n"), stdout );
  840       fputs( _("\
  841  -a filename, --addbook=filename   compile book.bin from pgn book 'filename'\n"), stdout );
  842       fputs( _("\
  843  -g, --graphic      enable graphic mode\n"), stdout );
  844       fputs( _("\
  845 \n"), stdout );
  846       fputs( _("\
  847  Options xboard and post are accepted without leading dashes\n\
  848  for backward compatibility.\n\
  849 \n"), stdout );
  850       fputs( _("\
  851  Moves are accepted either in standard algebraic notation (SAN) or\n\
  852  in coordinate algebraic notation.\n\
  853 \n"), stdout );
  854       fputs( _("\
  855  The file 'gnuchess.ini' allows setting config options if --uci is not\n\
  856  used. See 'info gnuchess' for details. The file is looked for in three\n\
  857  locations according to this precedence: current directory, the\n\
  858  directory pointed to by environment variable GNUCHESS_PKGDATADIR,\n\
  859  or the package data directory stated at configure time.\n\
  860 \n"), stdout );
  861       fputs( _("\
  862 Report bugs to <bug-gnu-chess@gnu.org>.\n\
  863 \n"), stdout );
  864      }
  865 
  866 
  867 /* Play variant, we instruct interface in protover we play normal */
  868 void cmd_variant(void) {}
  869 
  870 /* TODO Not in 5.08 */
  871 void cmd_usermove(void)
  872 {
  873   /* TODO: Remove the first SetDataToEngine */
  874   /*SetDataToEngine( token[0] );*/
  875    leaf *ptr;
  876    ptr = ValidateMove (token[1]);
  877    if (ptr != NULL) {
  878      /* Since the user entered a move:
  879       * 1. The move must be sent to the engine.
  880       * 2. A reply is expected from the engine.
  881       */
  882      SetUserInputValidMove( 1 );
  883      SetDataToEngine( token[0] );
  884      pgnloaded = 0;
  885      ExpectAnswerFromEngine( true );
  886      SANMove (ptr->move, 1);
  887      MakeMove (board.side, &ptr->move);
  888      strcpy (Game[GameCnt].SANmv, SANmv);
  889      printf("%d. ",GameCnt/2+1);
  890      printf("%s",token[1]);
  891      if (ofp != stdout) {
  892        fprintf(ofp,"%d. ",GameCnt/2+1);
  893        fprintf(ofp,"%s",token[1]);
  894      }
  895      putchar('\n');
  896      fflush(stdout);
  897      if (ofp != stdout) {
  898        fputc('\n',ofp);
  899        fflush(ofp);
  900      }
  901      if (!(flags & XBOARD)) ShowBoard ();
  902      SET (flags, THINK);
  903    }
  904    else {
  905      /*
  906       * Must Output Illegal move to prevent Xboard accepting illegal
  907       * en passant captures and other subtle mistakes
  908       */
  909      printf(_("Invalid move: %s\n"),token[1]);
  910      fflush(stdout);
  911    }
  912 }
  913 
  914 void cmd_version(void)
  915 {
  916    if (!(flags & XBOARD))
  917      printf ("%s %s\n", PROGRAM, VERSION);
  918    else
  919      printf ("Chess\n");
  920 }
  921 
  922 void cmd_coords(void) {
  923     printf(_("Coordinate display enabled.\n"));
  924     coords = 1;
  925 }
  926 
  927 void cmd_nocoords(void) {
  928     printf(_("Coordinate display disabled.\n"));
  929     coords = 0;
  930 }
  931 
  932 void cmd_white(void)
  933 {
  934  /*
  935   * No longer used by Xboard but requested as a feature
  936   */
  937   printf( _("Command 'white' is currently not supported.\n") );
  938 }
  939 
  940 void cmd_xboard(void)
  941 {
  942   SetDataToEngine( "xboard" );
  943   if (tokeneq (token[1], "off"))
  944     CLEAR (flags, XBOARD);
  945   else if (tokeneq (token[1], "on"))
  946     SET (flags, XBOARD);
  947   else if (!(flags & XBOARD)) { /* set if unset and only xboard called */
  948     SET (flags, XBOARD);        /* like in xboard/winboard usage */
  949   }
  950 }
  951 
  952 /*
  953  * Command with subcommands, could write secondary method
  954  * tables here
  955  */
  956 
  957 void cmd_show (void)
  958 /************************************************************************
  959  *
  960  *  The show command driver section.
  961  *
  962  ************************************************************************/
  963 {
  964    /* TODO Remove gettext support */
  965    if (tokeneq (token[1], "board"))
  966       ShowBoard ();
  967    else if (tokeneq (token[1], "rating"))
  968    {
  969       printf(_("My rating = %d\n"),myrating);
  970       printf(_("Opponent rating = %d\n"),opprating);
  971    }
  972    else if (tokeneq (token[1], _("time")))
  973       ShowTime ();
  974    else if (tokeneq (token[1], _("moves"))) {
  975       GenCnt = 0;
  976       TreePtr[2] = TreePtr[1];
  977       GenMoves (1);
  978       ShowMoveList (1);
  979       printf (_("No. of moves generated = %ld\n"), GenCnt);
  980    }
  981    else if (tokeneq (token[1], "escape")) {
  982       GenCnt = 0;
  983       TreePtr[2] = TreePtr[1];
  984       GenCheckEscapes (1);
  985       ShowMoveList (1);
  986       printf (_("No. of moves generated = %ld\n"), GenCnt);
  987    }
  988    else if (tokeneq (token[1], "noncapture"))
  989    {
  990       GenCnt = 0;
  991       TreePtr[2] = TreePtr[1];
  992       GenNonCaptures (1);
  993       FilterIllegalMoves (1);
  994       ShowMoveList (1);
  995       printf (_("No. of moves generated = %ld\n"), GenCnt);
  996    }
  997    else if (tokeneq (token[1], "capture"))
  998    {
  999       GenCnt = 0;
 1000       TreePtr[2] = TreePtr[1];
 1001       GenCaptures (1);
 1002       FilterIllegalMoves (1);
 1003       ShowMoveList (1);
 1004       printf (_("No. of moves generated = %ld\n"), GenCnt);
 1005    }
 1006    else if (tokeneq (token[1], "eval") || tokeneq (token[1], "score"))
 1007    {
 1008       printf( _("Command 'show eval/score' is currently not supported.\n") );
 1009       return;
 1010    }
 1011    else if (tokeneq (token[1], "game"))
 1012      ShowGame ();
 1013    else if (tokeneq (token[1], "pin"))
 1014    {
 1015       printf( _("Command 'show pin' is currently not supported.\n") );
 1016       return;
 1017    }
 1018 }
 1019 
 1020 void cmd_test (void)
 1021 /*************************************************************************
 1022  *
 1023  *  The test command driver section.
 1024  *
 1025  *************************************************************************/
 1026 {
 1027   printf( _("Command 'test' is currently not supported.\n") );
 1028 }
 1029 
 1030 /*
 1031  * This is more or less copied from the readme, and the
 1032  * parser is not very clever, so the lines containing
 1033  * command names should not be indented, the lines with
 1034  * explanations following them should be indented. Do not
 1035  * use tabs for indentation, only spaces. CAPITALS are
 1036  * reserved for parameters in the command names. The
 1037  * array must be terminated by two NULLs.
 1038  *
 1039  * This one should be integrated in the method table.
 1040  * (Very much like docstrings in Lisp.)
 1041  */
 1042 
 1043 static const char * const helpstr[] = {
 1044    "quit",
 1045    gettext_noop(" Quits the program."),
 1046    "exit",
 1047    gettext_noop(" In analysis mode this stops analysis, otherwise it quits the program."),
 1048    "help",
 1049    gettext_noop(" Produces a help blurb corresponding to this list of commands."),
 1050    "book",
 1051    gettext_noop(" add - compiles book.bin from a pgn book file"),
 1052    gettext_noop(" on - enables use of book (default)"),
 1053    gettext_noop(" off - disables use of book"),
 1054    gettext_noop(" worst - plays worst move from book"),
 1055    gettext_noop(" best - plays best move from book"),
 1056    gettext_noop(" prefer - same as 'book on' (default)"),
 1057    gettext_noop(" random - plays any move from book"),
 1058    "version",
 1059    gettext_noop(" Prints out the version of this program."),
 1060    "previous",
 1061    "p",
 1062    gettext_noop(" Backs up one move in pgn loaded game."),
 1063    "pgnsave FILENAME",
 1064    gettext_noop(" Saves the game so far from memory to the file."),
 1065    "pgnload FILENAME",
 1066    gettext_noop(" Loads the game in the file into memory."),
 1067    "pgnreplay FILENAME",
 1068    gettext_noop(" Loads the game in the file into memory, and enables\n"
 1069                 " the commands 'first', 'last', 'next', 'previous'."),
 1070    "next",
 1071    "n",
 1072    gettext_noop(" Advances one move in pgn loaded game."),
 1073    "first",
 1074    gettext_noop(" Goes to begin position of pgn loaded game."),
 1075    "last",
 1076    gettext_noop(" Goes to end position of pgn loaded game."),
 1077    "force",
 1078    "manual",
 1079    gettext_noop(" Makes the program stop moving. You may now enter moves\n"
 1080                 " to reach some position in the future."),
 1081    " ",
 1082    "white",
 1083    gettext_noop(" Program plays white."),
 1084    "black",
 1085    gettext_noop(" Program plays black."),
 1086    "go",
 1087    gettext_noop(" Computer takes whichever side is on move and begins its\n"
 1088                 " thinking immediately."),
 1089    "post",
 1090    gettext_noop(" Arranges for verbose thinking output showing variation, score,\n"
 1091                 " time, depth, etc."),
 1092    "nopost",
 1093    gettext_noop(" Turns off verbose thinking output."),
 1094    "name NAME",
 1095    gettext_noop(" Lets you input your name. Also writes the log.nnn and\n"
 1096                 " corresponding game.nnn files. For details please see\n"
 1097                 " the auxiliary file format sections."),
 1098    "result",
 1099    gettext_noop(" Mostly used by Internet Chess Server."),
 1100    "activate",
 1101    gettext_noop(" This command reactivates a game that has been terminated automatically\n"
 1102                 " due to checkmate or no more time on the clock. However, it does not\n"
 1103                 " alter those conditions. So you would have to undo a move or two, or\n"
 1104                 " add time to the clock with 'level' or 'time'."),
 1105    "rating COMPUTERRATING OPPONENTRATING",
 1106    gettext_noop(" Inputs the estimated rating for computer and for its opponent."),
 1107    "new",
 1108    gettext_noop(" Sets up a new game (i.e. pieces in original positions)."),
 1109    "time",
 1110    gettext_noop(" Inputs time left in game for computer in hundredths of a second.\n"
 1111                 " Mostly used by Internet Chess Server."),
 1112    "hash",
 1113    gettext_noop(" on - enables using the memory hash table to speed up search"),
 1114    gettext_noop(" off - disables the memory hash table"),
 1115    "memory N",
 1116    gettext_noop(" Sets the hash table to permit storage of N MB."),
 1117    "null",
 1118    gettext_noop(" on - enables using the null-move heuristic to speed up search"),
 1119    gettext_noop(" off - disables using the null-move heuristic"),
 1120    "xboard",
 1121    gettext_noop(" on - enables use of xboard/winboard"),
 1122    gettext_noop(" off - disables use of xboard/winboard"),
 1123    "depth N",
 1124    gettext_noop(" Sets the program to look N ply (half-moves) deep for every\n"
 1125                 " search it performs. If there is a checkmate or other condition\n"
 1126                 " that does not allow that depth, then it will not be."),
 1127    "level MOVES MINUTES INCREMENT",
 1128    gettext_noop(" Sets time control to be MOVES in MINUTES, with each move giving\n"
 1129                 " an INCREMENT (in seconds, i.e. a Fischer-style clock)."),
 1130    "load",
 1131    "epdload",
 1132    gettext_noop(" Loads a position in EPD format from disk into memory."),
 1133    "save",
 1134    "epdsave",
 1135    gettext_noop(" Saves game position into EPD format from memory to disk."),
 1136    "switch",
 1137    gettext_noop(" Switches side to move."),
 1138    "solve FILENAME",
 1139    "solveepd FILENAME",
 1140    gettext_noop(" Solves the positions in FILENAME."),
 1141    "remove",
 1142    gettext_noop(" Backs up two moves in game history."),
 1143    "undo",
 1144    gettext_noop(" Backs up one move in game history."),
 1145    "usage",
 1146    gettext_noop(" Displays command line syntax."),
 1147    "show",
 1148    gettext_noop(" board - displays the current board"),
 1149    gettext_noop(" time - displays the time settings"),
 1150    gettext_noop(" moves - shows all moves using one call to routine"),
 1151    gettext_noop(" escape - shows moves that escape from check using one call to routine"),
 1152    gettext_noop(" noncapture - shows non-capture moves"),
 1153    gettext_noop(" capture - shows capture moves"),
 1154    gettext_noop(" eval [or score] - shows the evaluation per piece and overall"),
 1155    gettext_noop(" game - shows moves in game history"),
 1156    gettext_noop(" pin - shows pinned pieces"),
 1157    "test",
 1158    gettext_noop(" movelist - reads in an epd file and shows legal moves for its entries"),
 1159    gettext_noop(" capture - reads in an epd file and shows legal captures for its entries"),
 1160    gettext_noop(" movegenspeed - tests speed of move generator"),
 1161    gettext_noop(" capturespeed - tests speed of capture move generator"),
 1162    gettext_noop(" eval - reads in an epd file and shows evaluation for its entries"),
 1163    gettext_noop(" evalspeed - tests speed of the evaluator"),
 1164    "bk",
 1165    gettext_noop(" Shows moves from opening book."),
 1166    "graphic",
 1167    gettext_noop(" Enables display board in graphic mode."),
 1168    "nographic",
 1169    gettext_noop(" Disables graphic mode and display classical view."),
 1170    "coords",
 1171    gettext_noop(" Displays the chessboard rank and file in both graphic and classical views."),
 1172    "nocoords",
 1173    gettext_noop(" Does not display the chessboard rank nor file in either mode (graphic nor classical)."),
 1174    NULL,
 1175    NULL
 1176 };
 1177 
 1178 void cmd_help (void)
 1179 /**************************************************************************
 1180  *
 1181  *  Display all the help commands.
 1182  *
 1183  **************************************************************************/
 1184 {
 1185    const char * const *p;
 1186    int count, len;
 1187 
 1188    if (strlen(token[1])>0) {
 1189       for (p=helpstr, count=0; *p; p++) {
 1190         if (strncmp(*p, token[1], strlen(token[1])) == 0) {
 1191            puts(*p);
 1192            while (*++p && **p != ' ') /* Skip aliases */ ;
 1193            for (; *p && **p == ' '; p++) {
 1194               puts(_(*p));
 1195            }
 1196            return;
 1197         }
 1198       }
 1199       printf(_("Help for command '%s' not found.\n\n"), token[1]);
 1200    }
 1201    printf(_("List of commands: (help COMMAND to get more help)\n"));
 1202    for (p=helpstr, count=0; *p; p++) {
 1203       len = strcspn(*p, " ");
 1204       if (len > 0) {
 1205         count += printf("%.*s  ", len, *p);
 1206         if (count > 60) {
 1207            count = 0;
 1208            puts("");
 1209         }
 1210       }
 1211    }
 1212    puts("");
 1213 }
 1214 
 1215 /*
 1216  * Try a method table, one could also include the documentation
 1217  * strings here
 1218  */
 1219 
 1220 struct methodtable {
 1221   const char *name;
 1222   void (*method) (void);
 1223 };
 1224 
 1225 /* Last entry contains two NULL pointers */
 1226 
 1227 /* List commands we don't implement to avoid illegal moving them */
 1228 
 1229 const struct methodtable commands[] = {
 1230   { "?", cmd_movenow },
 1231   { "accepted", cmd_accepted },
 1232   { "activate", cmd_activate },
 1233   { "analyze", cmd_analyze },
 1234   { "bk", cmd_bk },
 1235   { "black", cmd_black },
 1236   { "book", cmd_book },
 1237   { "depth", cmd_depth },
 1238   { "easy", cmd_easy },
 1239   { "edit", cmd_edit },
 1240   { "epdload", cmd_load },
 1241   { "epdsave", cmd_save },
 1242   { "exit", cmd_exit },
 1243   { "force", cmd_force },
 1244   { "go", cmd_go },
 1245   { "graphic", cmd_graphic },
 1246   { "hard", cmd_hard },
 1247   { "hash", cmd_hash },
 1248   { "help", cmd_help },
 1249   { "hint", cmd_hint },
 1250   { "ics", cmd_ics },
 1251   { "last", cmd_last },
 1252   { "level", cmd_level },
 1253   { "list", cmd_list },
 1254   { "load", cmd_load },
 1255   { "manual", cmd_manual },
 1256   { "memory", cmd_memory },
 1257   { "name", cmd_name },
 1258   { "new", cmd_new },
 1259   { "next", cmd_next },
 1260   { "n", cmd_next },
 1261   { "nographic", cmd_nographic  },
 1262   { "nopost", cmd_nopost },
 1263   { "null", cmd_null },
 1264   { "otim", cmd_otim },
 1265   { "pgnload", cmd_pgnload },
 1266   { "pgnreplay", cmd_pgnreplay },
 1267   { "pgnsave", cmd_pgnsave },
 1268   { "ping", cmd_ping },
 1269   { "post", cmd_post },
 1270   { "previous", cmd_previous },
 1271   { "p", cmd_previous },
 1272   { "first", cmd_first },
 1273   { "protover", cmd_protover },
 1274   { "quit", cmd_quit },
 1275   { "random", cmd_random },
 1276   { "rating", cmd_rating },
 1277   { "rejected", cmd_rejected },
 1278   { "remove", cmd_remove },
 1279   { "result", cmd_result },
 1280   { "save", cmd_save },
 1281   { "setboard", cmd_setboard },
 1282   { "show", cmd_show },
 1283   { "solve", cmd_solve },
 1284   { "solveepd", cmd_solve },
 1285   { "st", cmd_st },
 1286   { "switch", cmd_switch },
 1287   { "test", cmd_test },
 1288   { "time", cmd_time },
 1289   { "undo", cmd_undo },
 1290   { "usage", cmd_usage },
 1291   { "usermove", cmd_usermove },
 1292   { "variant", cmd_variant },
 1293   { "version", cmd_version },
 1294   { "white", cmd_white },
 1295   { "xboard", cmd_xboard },
 1296   { "coords", cmd_coords},
 1297   { "nocoords", cmd_nocoords},
 1298   { NULL, NULL }
 1299 };
 1300 
 1301 void parse_input(void)
 1302 /*************************************************************************
 1303  *
 1304  *  This is the main user command interface driver.
 1305  *
 1306  *************************************************************************/
 1307 {
 1308    leaf *ptr;
 1309    const struct methodtable * meth;
 1310 
 1311    dbg_printf("parse_input() called, inputstr = *%s*\n", inputstr);
 1312 
 1313    /* Initialize variables used to send messages to the engine */
 1314    SetDataToEngine( "" );
 1315    ExpectAnswerFromEngine( false );
 1316    SetUserInputValidMove( 0 );
 1317    ChangeColor( false );
 1318 
 1319    split_input();
 1320 
 1321    for (meth = commands; meth->name != NULL; meth++) {
 1322      if (tokeneq(token[0], meth->name)) {
 1323        meth->method();
 1324        return;
 1325      }
 1326    }
 1327 
 1328    /* OK, no known command, this should be a move */
 1329    char cleanMove[MAXSTR]="";
 1330    ptr = ValidateMove (token[0], cleanMove);
 1331    if (ptr != NULL) {
 1332      /* Since the user entered a move:
 1333       * 1. The move must be sent to the engine.
 1334       * 2. A reply is expected from the engine.
 1335       */
 1336      SetUserInputValidMove( 1 );
 1337      SetDataToEngine( cleanMove );
 1338      pgnloaded = 0;
 1339      ExpectAnswerFromEngine( true );
 1340      SANMove (ptr->move, 1);
 1341      MakeMove (board.side, &ptr->move);
 1342      strcpy (Game[GameCnt].SANmv, SANmv);
 1343      printf("%d. ",GameCnt/2+1);
 1344      printf("%s",token[0]);
 1345      if (ofp != stdout) {
 1346        fprintf(ofp,"%d. ",GameCnt/2+1);
 1347        fprintf(ofp,"%s",token[0]);
 1348      }
 1349      putchar('\n');
 1350      fflush(stdout);
 1351      if (ofp != stdout) {
 1352        fputc('\n',ofp);
 1353        fflush(ofp);
 1354      }
 1355      if (!(flags & XBOARD)) ShowBoard ();
 1356      SET (flags, THINK);
 1357    }
 1358    else {
 1359      /*
 1360       * Must Output Illegal move to prevent Xboard accepting illegal
 1361       * en passant captures and other subtle mistakes
 1362       */
 1363      printf(_("Invalid move: %s\n"),token[0]);
 1364      fflush(stdout);
 1365    }
 1366 }
 1367 
 1368 void check_board()
 1369 /*************************************************************************
 1370  *
 1371  *  When the board is changed by commands, call the Validation
 1372  *  routine, and if it fails set flags to prevent the analysis of
 1373  *  illegal positions, as the code is not robust against the
 1374  *  analysis of such positions (To Do).
 1375  *
 1376  *************************************************************************/
 1377 {
 1378   if (!ValidateBoard()) {
 1379     SET (flags, ENDED);
 1380     if (flags & XBOARD) {
 1381     printf ("telluser Board is wrong!\n");
 1382         fflush(stdout);
 1383     } else {
 1384         printf (_("Board is wrong!\n"));
 1385     }
 1386   }
 1387 }
 1388