Implement exclude-moves feature
[bonanza.git] / proce.c
1 #include <ctype.h>
2 #include <limits.h>
3 #include <math.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include "shogi.h"
8
9 /* unacceptable when the program is thinking, or quit pondering */
10 #define AbortDifficultCommand                                              \
11           if ( game_status & flag_thinking )                               \
12             {                                                              \
13               str_error = str_busy_think;                                  \
14               return -2;                                                   \
15             }                                                              \
16           else if ( game_status & ( flag_pondering | flag_puzzling ) )     \
17             {                                                              \
18               game_status |= flag_quit_ponder;                             \
19               return 2;                                                    \
20             }
21
22 #if defined(MINIMUM)
23 #  define CmdBook(x,y) cmd_book(y);
24 static int CONV cmd_book( char **lasts );
25 #else
26 #  define CmdBook(x,y) cmd_book(x,y);
27 static int CONV cmd_learn( tree_t * restrict ptree, char **lasts );
28 static int CONV cmd_book( tree_t * restrict ptree, char **lasts );
29 #endif
30
31 #if ! defined(NO_STDOUT)
32 static int CONV cmd_stress( char **lasts );
33 #endif
34
35 #if defined(CSA_LAN)
36 static int CONV proce_csalan( tree_t * restrict ptree );
37 static int CONV cmd_connect( tree_t * restrict ptree, char **lasts );
38 static int CONV cmd_sendpv( char **lasts );
39 #endif
40
41 #if defined(MNJ_LAN)
42 static int CONV proce_mnj( tree_t * restrict ptree );
43 static int CONV cmd_mnjignore( tree_t *restrict ptree, char **lasts );
44 static int CONV cmd_mnj( char **lasts );
45 static int CONV cmd_mnjmove( tree_t * restrict ptree, char **lasts,
46                              int num_alter );
47 #endif
48
49 #if defined(USI)
50 static int CONV proce_usi( tree_t * restrict ptree );
51 static int CONV usi_posi( tree_t * restrict ptree, char **lasts );
52 static int CONV usi_go( tree_t * restrict ptree, char **lasts );
53 static int CONV usi_ignore( tree_t * restrict ptree, char **lasts );
54 #endif
55
56 #if defined(TLP)
57 static int CONV cmd_thread( char **lasts );
58 #endif
59
60 #if defined(MPV)
61 static int CONV cmd_mpv( tree_t * restrict ptree, char **lasts );
62 #endif
63
64 #if defined(DFPN)
65 static int CONV cmd_dfpn( tree_t * restrict ptree, char **lasts );
66 #endif
67
68 #if defined(DFPN_CLIENT)
69 static int CONV cmd_dfpn_client( tree_t * restrict ptree, char **lasts );
70 #endif
71
72 static int CONV proce_cui( tree_t * restrict ptree );
73 static int CONV cmd_usrmove( tree_t * restrict ptree, const char *str_move,
74                              char **last );
75 static int CONV cmd_outmove( tree_t * restrict ptree );
76 static int CONV cmd_move_now( void );
77 static int CONV cmd_ponder( char **lasts );
78 static int CONV cmd_limit( char **lasts );
79 static int CONV cmd_quit( void );
80 static int CONV cmd_beep( char **lasts );
81 static int CONV cmd_peek( char **lasts );
82 static int CONV cmd_stdout( char **lasts );
83 static int CONV cmd_newlog( char **lasts );
84 static int CONV cmd_hash( char **lasts );
85 static int CONV cmd_ping( void );
86 static int CONV cmd_suspend( void );
87 static int CONV cmd_problem( tree_t * restrict ptree, char **lasts );
88 static int CONV cmd_display( tree_t * restrict ptree, char **lasts );
89 static int CONV cmd_move( tree_t * restrict ptree, char **lasts );
90 static int CONV cmd_new( tree_t * restrict ptree, char **lasts );
91 static int CONV cmd_read( tree_t * restrict ptree, char **lasts );
92 static int CONV cmd_resign( tree_t * restrict ptree, char **lasts );
93 static int CONV cmd_undo( tree_t * restrict ptree );    // [HGM] undo
94 static int CONV cmd_time( char **lasts );
95 static int CONV cmd_undo( tree_t * restrict ptree );    // [HGM] undo
96 static int CONV cmd_analyze( tree_t * restrict ptree ); // [HGM] analyze
97 static int CONV cmd_exit( void );
98
99
100 int CONV is_move( const char *str )
101 {
102   if ( isdigit( (int)str[0] ) && isdigit( (int)str[1] )
103        && isdigit( (int)str[2] ) && isdigit( (int)str[3] )
104        && isupper( (int)str[4] ) && isupper( (int)str[5] )
105        && str[6] == '\0' ) { return 1; }
106
107   return 0;
108 }
109
110
111 int CONV
112 procedure( tree_t * restrict ptree )
113 {
114 #if defined(CSA_LAN)
115   if ( sckt_csa != SCKT_NULL ) { return proce_csalan( ptree ); }
116 #endif
117
118 #if defined(MNJ_LAN)
119   if ( sckt_mnj != SCKT_NULL ) { return proce_mnj( ptree ); }
120 #endif
121
122 #if defined(USI)
123   if ( usi_mode != usi_off ) { return proce_usi( ptree ); }
124 #endif
125
126   return proce_cui( ptree );
127 }
128
129 char *start_pos, start_data[512]; // [HGM] undo: for remembering start position
130 int move_list[1024], move_ptr;
131 char analyze_mode;
132 int all_moves[MAX_LEGAL_MOVES];
133
134 #ifdef XBOARD
135 #define IF(X) else if(!strcmp(command, X))
136
137 int myTime, hisTime, movesPerSession, inc, plyNr;
138 char xboard_mode;
139
140 int
141 xboard_to_CSA( tree_t * restrict ptree, char *in, char *out, int status )
142 {
143   char fromX=in[0], fromY=in[1], toX=in[2], toY=in[3], promo=in[4];
144   int piece=0, bonanza_move=0;
145   if(fromY == '@') { // drop (contains all info needed to convert it)
146     if(fromX >= 'a') fromX += 'A' - 'a';
147     switch(fromX) { // encode piece
148       case 'P': piece = pawn;   break;
149       case 'L': piece = lance;  break;
150       case 'N': piece = knight; break;
151       case 'S': piece = silver; break;
152       case 'G': piece = gold;   break;
153       case 'B': piece = bishop; break;
154       case 'R': piece = rook;   break;
155     }
156     bonanza_move = Drop2Move(piece) | To2Move( ('9' - toY)*9 + (toX - 'a') );
157     sprintf(out, "00%c%c%s", 'a'+'9'-toX, '1'+'9'-toY, astr_table_piece[piece]);
158   } else { // board move (need to figure out moved piece)
159     int from = ('9' - fromY)*9 + (fromX - 'a');
160     int flag = (promo == '+' ? FLAG_PROMO : 0);
161     piece = abs( BOARD[from] ); // this only works when not searching!
162 printf("# piece from board: %d\n", piece);fflush(stdout);
163     if( status & ( flag_pondering | flag_puzzling | flag_thinking ) ) {
164       int i, to = ('9' - toY)*9 + (toX - 'a'), l = (status == (flag_pondering | flag_thinking));
165       piece = 0; // kludge to force illegal CSA move
166       for( i = 0; l ? all_moves[i] : i < root_nmove; i++ ) { // determine the piece from the move list
167         int move = (l ? all_moves[i] : root_move_list[i].move);
168         if( I2To(move) != to ) continue;
169         if( I2From(move) != from ) continue;
170         if( (move & FLAG_PROMO) != flag ) continue;
171         piece = I2PieceMove( move ); // we found the move; take the piece from it
172         bonanza_move = move;
173         break;
174       }
175 printf("# piece corrected to %d\n", piece);fflush(stdout);
176     }
177     if( promo ) piece += promote;
178     sprintf(out, "%c%c%c%c%s", 'a'+'9'-fromX, '1'+'9'-fromY, 'a'+'9'-toX, '1'+'9'-toY, astr_table_piece[piece]);
179   }
180   return bonanza_move;
181 }
182
183 static void
184 update_exclude_list( tree_t * restrict ptree, int add, char *move_str )
185 { // [HGM] exclude: manage list of excluded moves
186   char dummy[20];
187   int i;
188   if( moves_ignore[0] == MOVE_NA ) { // nothing is excluded yet; make a copy of root move list;
189     for( i = 0; i < root_nmove; i++) all_moves[i] = root_move_list[i].move;
190     all_moves[i] = 0;
191   }
192   if ( ! strcmp(move_str, "all") ) { // all moves
193     if( add ) { // copy entire list of legal moves
194       for( i = 0; i < root_nmove; i++ ) moves_ignore[i] = all_moves[i];
195     } else moves_ignore[0] = MOVE_NA; // clear list
196   } else { // single move
197     int move = xboard_to_CSA( ptree, move_str, dummy, flag_pondering | flag_thinking); // kludge with impossible flag
198     for( i = 0; moves_ignore[i] != MOVE_NA; i++ ) if( move == moves_ignore[i] ) break;
199     if( add ) { // we must add the move
200       if( moves_ignore[i] != MOVE_NA ) return; // but it was already in list
201       if( i >= MAX_LEGAL_MOVES - 2 ) return; // overflow
202       moves_ignore[i] = move; moves_ignore[i+1] = MOVE_NA; // append move
203     } else { // we must delete the move
204       if( moves_ignore[i] == MOVE_NA ) return; // but it was not there
205       while( (moves_ignore[i] = moves_ignore[i+1]) ) i++; // squeeze it out
206     }
207   }
208 }
209
210 static void
211 SetTimes(void)
212 { // set white and black times from own and opponent time.
213   int moves;
214   if(movesPerSession <= 0) moves = 35; else {
215     moves = - plyNr/2;
216     while(moves <= 0) moves += movesPerSession;
217   }
218   time_limit = (myTime-inc-30)/(moves+2) + inc;
219   time_max_limit = 3*time_limit;
220   if(time_max_limit > myTime - 30)time_max_limit = myTime - 30; // keep 0.3 sec margin, as Bonanza reads the clock infrequently
221   time_limit *= 10; // msec
222   time_max_limit *= 10;
223 Out("# moves=%d, time=%d inc=%d t=%d, max=%d\n", moves, myTime, inc, time_limit, time_max_limit);
224 }
225
226 static int
227 proce_xboard(char *line, const char *command, tree_t * restrict ptree)
228 { // [HGM] added to make Bonanza.exe a native WinBoard engine
229   int value = -100000;
230   static char forceMode = 0;
231   sscanf(line + strlen(command) + 1, "%d", &value);
232 Out("# command = '%s'\n", line);
233   if(0) ;
234   IF("protover") {
235 #if defined(MPV)
236                    Out("feature option=\"MultiPV -spin 1 1 100\"\n");
237                    Out("feature option=\"centi-Pawn margin -spin 200 0 25000\"\n");
238 #endif
239                    Out("feature variants=\"shogi\" usermove=1 myname=\"Bonanza " BNZ_VER
240                        "\" memory=1 smp=1 debug=1 colors=0 setboard=1 ping=1 sigint=0 exclude=1 done=1\n");
241                  }
242   IF("new")      { forceMode = plyNr = 0; SetTimes(); return 0; }
243   IF("easy")     { strcpy(line, "ponder off"); return 0; }
244   IF("hard")     { strcpy(line, "ponder on");  return 0; }
245   IF("post")     { ; }
246   IF("nopost")   { ; }
247   IF("time")     { sscanf(line+5, "%d", &myTime); }
248   IF("otim")     { sscanf(line+5, "%d", &hisTime); }
249   IF("force")    { forceMode = 1; }
250   IF("go")       { forceMode = 0; SetTimes(); plyNr++; strcpy(line, "move"); return 0; }
251   IF("memory")   { ; }
252   IF("cores")    { sprintf(line, "tlp num %d", value); return 0; }
253   IF("sd")       { sprintf(line, "limit depth %d", value); return 0; }
254   IF("st")       { ; }
255   IF("quit")     { return 0; }
256   IF("analyze")  { return 0; }
257   IF("exit")     { return 0; }
258   IF("variant")  { /* ignore, since it must be Shogi */; }
259   IF("setboard") { ; }
260   IF("option")   {
261                    if(sscanf(line+7, "MultiPV=%d", &value) == 1) { sprintf(line, "mpv num %d", value); return 0; }
262                    if(sscanf(line+7, "centi-Pawn margin=%d", &value) == 1) { sprintf(line, "mpv width %d", value); return 0; }
263                  }
264   IF("level")    { int min, sec; float fsec=0.;
265                    if(sscanf(line+6, "%d %d:%d %f", &movesPerSession, &min, &sec, &fsec) != 4)
266                       sscanf(line+6, "%d %d %f", &movesPerSession, &min, &fsec);
267                    min = 60*min + sec; myTime = hisTime = 100*min; inc = 100 * fsec;
268                  }
269   IF("usermove") { char buf[20];
270                    xboard_to_CSA( ptree, line+9, buf, game_status );
271                    if(forceMode || analyze_mode) strcpy(line, "move "), line += 5; else plyNr++, SetTimes();
272                    strcpy( line, buf );
273                    plyNr++;
274                    return 0;
275                  }
276   IF("undo")     { return 0; }
277   IF("remove")   { ; }
278   IF("ping")     { Out("pong %d\n", value); }
279   IF("exclude")  { update_exclude_list( ptree, 1, line+8 ); strcpy(line, "analyze"); return 0; }
280   IF("include")  { update_exclude_list( ptree, 0, line+8 ); strcpy(line, "analyze"); return 0; }
281   return 1;
282 }
283 #endif
284
285 static int CONV proce_cui( tree_t * restrict ptree )
286 {
287   const char *token;
288   char *last;
289
290   token = strtok_r( str_cmdline, str_delimiters, &last );
291
292   if ( token == NULL || *token == '#' ) { return 1; }
293 #ifdef XBOARD
294   { 
295     if(xboard_mode) {
296       if( proce_xboard(str_cmdline, token, ptree) )  return 1; // command already processed
297       Out("# translated command '%s'\n", str_cmdline);         // command translated for processing by Bonanza
298       token = strtok_r( str_cmdline, str_delimiters, &last );  // redo parsing
299     } else
300     if ( ! strcmp( token, "xboard" ) )  { xboard_mode = 1; game_status |= flag_noprompt; return 1; }
301   }
302 #endif
303   if ( ! strcmp( token, "analyze" ) )   { return cmd_analyze( ptree ); } // [HGM] analyze
304   if ( ! strcmp( token, "exit" ) )      { return cmd_exit(); }           // [HGM] analyze
305   if ( ! strcmp( token, "move" ) )      { return cmd_move( ptree, &last ); }
306   if ( ! strcmp( token, "undo" ) )      { return cmd_undo( ptree ); }    // [HGM] undo
307 #if defined(MPV)
308   if ( ! strcmp( token, "mpv" ) )       { return cmd_mpv( ptree, &last ); }
309 #endif
310   analyze_mode = 0; // [HGM] analyze: all other commands terminate analysis
311   if ( is_move( token ) ) { return cmd_usrmove( ptree, token, &last ); }
312   if ( ! strcmp( token, "s" ) )         { return cmd_move_now(); }
313   if ( ! strcmp( token, "beep" ) )      { return cmd_beep( &last); }
314   if ( ! strcmp( token, "book" ) )      { return CmdBook( ptree, &last ); }
315   if ( ! strcmp( token, "display" ) )   { return cmd_display( ptree, &last ); }
316   if ( ! strcmp( token, "hash" ) )      { return cmd_hash( &last ); }
317   if ( ! strcmp( token, "limit" ) )     { return cmd_limit( &last ); }
318   if ( ! strcmp( token, "new" ) )       { return cmd_new( ptree, &last ); }
319   if ( ! strcmp( token, "outmove" ) )   { return cmd_outmove( ptree ); }
320   if ( ! strcmp( token, "peek" ) )      { return cmd_peek( &last ); }
321   if ( ! strcmp( token, "stdout" ) )    { return cmd_stdout( &last ); }
322   if ( ! strcmp( token, "ping" ) )      { return cmd_ping(); }
323   if ( ! strcmp( token, "ponder" ) )    { return cmd_ponder( &last ); }
324   if ( ! strcmp( token, "problem" ) )   { return cmd_problem( ptree, &last ); }
325   if ( ! strcmp( token, "quit" ) )      { return cmd_quit(); }
326   if ( ! strcmp( token, "read" ) )      { return cmd_read( ptree, &last ); }
327   if ( ! strcmp( token, "resign" ) )    { return cmd_resign( ptree, &last ); }
328   if ( ! strcmp( token, "suspend" ) )   { return cmd_suspend(); }
329   if ( ! strcmp( token, "time" ) )      { return cmd_time( &last ); }
330   if ( ! strcmp( token, "newlog" ) )    { return cmd_newlog( &last ); }
331 #if defined(CSA_LAN)
332   if ( ! strcmp( token, "connect" ) )   { return cmd_connect( ptree, &last ); }
333   if ( ! strcmp( token, "sendpv" ) )    { return cmd_sendpv( &last ); }
334 #endif
335 #if defined(MNJ_LAN)
336   if ( ! strcmp( token, "mnj" ) )       { return cmd_mnj( &last ); }
337 #endif
338 #if defined(DFPN)
339   if ( ! strcmp( token, "dfpn" ) )      { return cmd_dfpn( ptree, &last ); }
340 #endif
341 #if defined(DFPN_CLIENT)
342   if ( ! strcmp( token, "dfpn_client")) { return cmd_dfpn_client( ptree,
343                                                                   &last ); }
344 #endif
345 #if defined(TLP)
346   if ( ! strcmp( token, "tlp" ) )       { return cmd_thread( &last ); }
347 #endif
348 #if ! defined(NO_STDOUT)
349   if ( ! strcmp( token, "stress" ) )    { return cmd_stress( &last ); }
350 #endif
351 #if ! defined(MINIMUM)
352   if ( ! strcmp( token, "learn" ) )     { return cmd_learn( ptree, &last ); }
353 #endif
354
355   str_error = str_bad_cmdline;
356   return -2;
357 }
358
359
360 #if defined(CSA_LAN)
361 static int CONV proce_csalan( tree_t * restrict ptree )
362 {
363   const char *token;
364   char *last;
365
366   token = strtok_r( str_cmdline, str_delimiters, &last );
367     
368   if ( token == NULL ) { return 1; }
369   if ( *token == ach_turn[client_turn] && is_move( token+1 ) )
370     {
371       char *ptr;
372       long l;
373
374       token = strtok_r( NULL, str_delimiters, &last );
375       if ( token == NULL || *token != 'T' )
376         {
377           str_error = str_bad_cmdline;
378           return -1;
379         }
380       
381       l = strtol( token+1, &ptr, 0 );
382       if ( token+1 == ptr || l == LONG_MAX || l < 1 )
383         {
384           str_error = str_bad_cmdline;
385           return -1;
386         }
387
388       adjust_time( (unsigned int)l, client_turn );
389       Out( "  elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
390       return 1;
391     }
392   if ( *token == ach_turn[Flip(client_turn)] && is_move( token+1 ) )
393     {
394       return cmd_usrmove( ptree, token+1, &last );
395     }
396   if ( ! strcmp( token, str_resign ) ) { return cmd_resign( ptree, &last ); }
397   if ( ! strcmp( token, "#WIN" )
398        || ! strcmp( token, "#LOSE" )
399        || ! strcmp( token, "#DRAW" )
400        || ! strcmp( token, "#CHUDAN" ) )
401     {
402       if ( game_status & ( flag_thinking | flag_pondering | flag_puzzling ) )
403         {
404           game_status |= flag_suspend;
405           return 2;
406         }
407
408       if ( sckt_out( sckt_csa, "LOGOUT\n" ) < 0 ) { return -1; }
409       if ( sckt_recv_all( sckt_csa )        < 0 ) { return -1; }
410
411       ShutdownAll();
412       
413       if ( client_ngame == client_max_game ) { return cmd_quit(); }
414
415       return client_next_game( ptree, client_str_addr, (int)client_port );
416     }
417   
418   return 1;
419 }
420 #endif
421
422
423 #if defined(MNJ_LAN)
424 static int CONV proce_mnj( tree_t * restrict ptree )
425 {
426   const char *token;
427   char *last;
428   int iret;
429
430   token = strtok_r( str_cmdline, str_delimiters, &last );
431   if ( token == NULL ) { return 1; }
432
433   if ( ! strcmp( token, "new" ) )
434     {
435       iret = cmd_suspend();
436       if ( iret != 1 ) { return iret; }
437
438       mnj_posi_id = 0;
439       iret = cmd_new( ptree, &last );
440       if ( iret < 0 ) { return iret; }
441
442       moves_ignore[0] = MOVE_NA;
443       return analyze( ptree );
444     }
445   if ( ! strcmp( token, "ignore" ) ) { return cmd_mnjignore( ptree, &last ); }
446   if ( ! strcmp( token, "idle" ) )   { return cmd_suspend(); }
447   if ( ! strcmp( token, "alter" ) )  { return cmd_mnjmove( ptree, &last, 1 ); }
448   if ( ! strcmp( token, "retract" ) )
449     {
450       long l;
451       char *ptr;
452       const char *str = strtok_r( NULL, str_delimiters, &last );
453       if ( str == NULL )
454         {
455           str_error = str_bad_cmdline;
456           return -1;
457         }
458       l = strtol( str, &ptr, 0 );
459       if ( ptr == str || (long)NUM_UNMAKE < l )
460         {
461           str_error = str_bad_cmdline;
462           return -1;
463         }
464       
465       return cmd_mnjmove( ptree, &last, (int)l );
466     }
467   if ( ! strcmp( token, "move" ) )  { return cmd_mnjmove( ptree, &last, 0 ); }
468
469   str_error = str_bad_cmdline;
470   return -2;
471 }
472
473
474 static int CONV
475 cmd_mnjignore( tree_t *restrict ptree, char **lasts )
476 {
477   const char *token;
478   char *ptr;
479   int i;
480   unsigned int move;
481   long lid;
482
483
484   token = strtok_r( NULL, str_delimiters, lasts );
485   if ( token == NULL )
486     {
487       str_error = str_bad_cmdline;
488       return -1;
489     }
490   lid = strtol( token, &ptr, 0 );
491   if ( ptr == token || lid == LONG_MAX || lid < 1 )
492     {
493       str_error = str_bad_cmdline;
494       return -1;
495     }
496
497   AbortDifficultCommand;
498
499   for ( i = 0; ; i += 1 )
500     {
501       token = strtok_r( NULL, str_delimiters, lasts );
502       if ( token == NULL ) { break; }
503
504       if ( interpret_CSA_move( ptree, &move, token ) < 0 ) { return -1; }
505
506       moves_ignore[i] = move;
507     }
508   if ( i == 0 )
509     {
510       str_error = str_bad_cmdline;
511       return -1;
512     }
513   mnj_posi_id     = (int)lid;
514   moves_ignore[i] = MOVE_NA;
515
516   return analyze( ptree );
517 }
518
519
520 static int CONV
521 cmd_mnjmove( tree_t * restrict ptree, char **lasts, int num_alter )
522 {
523   const char *str1 = strtok_r( NULL, str_delimiters, lasts );
524   const char *str2 = strtok_r( NULL, str_delimiters, lasts );
525   char *ptr;
526   long lid;
527   unsigned int move;
528   int iret;
529
530   if ( sckt_mnj == SCKT_NULL ||  str1 == NULL || str2 == NULL )
531     {
532       str_error = str_bad_cmdline;
533       return -1;
534     }
535
536   lid = strtol( str2, &ptr, 0 );
537   if ( ptr == str2 || lid == LONG_MAX || lid < 1 )
538     {
539       str_error = str_bad_cmdline;
540       return -1;
541     }
542
543   AbortDifficultCommand;
544  
545   while ( num_alter )
546     {
547       iret = unmake_move_root( ptree );
548       if ( iret < 0 ) { return iret; }
549
550       num_alter -= 1;
551     }
552
553   iret = interpret_CSA_move( ptree, &move, str1 );
554   if ( iret < 0 ) { return iret; }
555     
556   iret = get_elapsed( &time_turn_start );
557   if ( iret < 0 ) { return iret; }
558
559   mnj_posi_id = (int)lid;
560
561   iret = make_move_root( ptree, move, ( flag_time | flag_rep
562                                         | flag_detect_hang ) );
563   if ( iret < 0 ) { return iret; }
564   
565 #  if ! defined(NO_STDOUT)
566   iret = out_board( ptree, stdout, 0, 0 );
567   if ( iret < 0 ) { return iret; }
568 #  endif
569
570   moves_ignore[0] = MOVE_NA;
571   return analyze( ptree );
572 }
573 #endif
574
575
576 static int CONV
577 do_analyze( tree_t * restrict ptree )
578 { // [HGM] analyze: do a ponder search on the current position
579   int iret;
580   if ( get_elapsed( &time_start ) < 0 ) { return -1; }
581   time_limit = time_max_limit = 1e9; // kludge: use huge time to mimic infinity
582 #ifdef XBOARD
583   if(xboard_mode) Out("1 0 0 0 New Search\n"); // make sure lower depth is emitted, so XBoard undestand new search started
584 #endif
585   game_status |= flag_pondering;
586   iret         = iterate( ptree );
587   game_status &= ~flag_pondering;
588   return iret;
589 }
590
591
592 static int CONV
593 cmd_undo( tree_t * restrict ptree )
594 { // [HGM] undo: restart the game, and feed all moves except the last
595   int i, last = move_ptr;
596   char *p = start_data;
597   if( move_ptr <= 0 ) {
598     str_error = "undo past start of game ignored";
599     return -2;
600   }
601
602   AbortDifficultCommand;
603
604   last--;
605   cmd_new( ptree, &p );
606   for(i=0; i<last; i++) {
607     make_move_root( ptree, move_list[i], 0);
608   }
609
610   moves_ignore[0] = MOVE_NA; // [HGM] exclude: exclude list cleared for new position
611   if ( analyze_mode ) return do_analyze ( ptree ); // [HGM] analyze: analysis should continue after undo
612
613   return 1;
614 }
615
616
617 static int CONV
618 cmd_analyze( tree_t * restrict ptree )
619 { // [HGM] analyze: switch on analyze mode, and start analyzing (also used to force a restart)
620   AbortDifficultCommand;
621
622   analyze_mode = 1;
623   return do_analyze( ptree );
624 }
625
626
627 static int CONV
628 cmd_exit( void )
629 { // [HGM] analyze: switch off analysis mode
630   if ( !analyze_mode ) {
631     str_error = "was not analyzing";
632     return -2;
633   }
634
635   if ( game_status & flag_pondering ) { game_status |= flag_quit_ponder; return 2; }
636   analyze_mode = 0;
637   moves_ignore[0] = MOVE_NA; // [HGM] exclude: exclude list cleared after analysis
638
639   return 1;
640 }
641
642
643 #if defined(USI)
644 static int CONV proce_usi( tree_t * restrict ptree )
645 {
646   const char *token;
647   char *lasts;
648   int iret;
649
650   token = strtok_r( str_cmdline, str_delimiters, &lasts );
651   if ( token == NULL ) { return 1; }
652
653   if ( ! strcmp( token, "usi" ) )
654     {
655       USIOut( "id name %s\n", str_myname );
656       USIOut( "id author Kunihito Hoki\n" );
657       USIOut( "usiok\n" );
658       return 1;
659     }
660
661   if ( ! strcmp( token, "isready" ) )
662     {
663       USIOut( "readyok\n", str_myname );
664       return 1;
665     }
666
667   if ( ! strcmp( token, "echo" ) )
668     {
669       USIOut( "%s\n", lasts );
670       return 1;
671     }
672
673   if ( ! strcmp( token, "ignore_moves" ) )
674     {
675       return usi_ignore( ptree, &lasts );
676     }
677
678   if ( ! strcmp( token, "genmove_probability" ) )
679     {
680       if ( get_elapsed( &time_start ) < 0 ) { return -1; }
681       return usi_root_list( ptree );
682     }
683
684   if ( ! strcmp( token, "go" ) )
685     {
686       iret = usi_go( ptree, &lasts );
687       moves_ignore[0] = MOVE_NA;
688       return iret;
689     }
690
691   if ( ! strcmp( token, "stop" ) )     { return cmd_move_now(); }
692   if ( ! strcmp( token, "position" ) ) { return usi_posi( ptree, &lasts ); }
693   if ( ! strcmp( token, "quit" ) )     { return cmd_quit(); }
694   
695   str_error = str_bad_cmdline;
696   return -1;
697 }
698
699
700 static int CONV
701 usi_ignore( tree_t * restrict ptree, char **lasts )
702 {
703   const char *token;
704   char str_buf[7];
705   int i;
706   unsigned int move;
707
708   AbortDifficultCommand;
709
710   for ( i = 0; ; i += 1 )
711     {
712       token = strtok_r( NULL, str_delimiters, lasts );
713       if ( token == NULL ) { break; }
714       
715       if ( usi2csa( ptree, token, str_buf ) < 0 )            { return -1; }
716       if ( interpret_CSA_move( ptree, &move, str_buf ) < 0 ) { return -1; }
717
718       moves_ignore[i] = move;
719     }
720
721   moves_ignore[i] = MOVE_NA;
722
723   return 1;
724 }
725
726
727 static int CONV
728 usi_go( tree_t * restrict ptree, char **lasts )
729 {
730   const char *token;
731   char *ptr;
732   int iret;
733   long l;
734
735   AbortDifficultCommand;
736
737   if ( game_status & mask_game_end )
738     {
739       str_error = str_game_ended;
740       return -1;
741     }
742   
743   token = strtok_r( NULL, str_delimiters, lasts );
744
745   if ( ! strcmp( token, "book" ) )
746     {
747       AbortDifficultCommand;
748       if ( usi_book( ptree ) < 0 ) { return -1; }
749
750       return 1;
751     }
752
753
754   if ( ! strcmp( token, "infinite" ) )
755     {
756       usi_byoyomi     = UINT_MAX;
757       depth_limit     = PLY_MAX;
758       node_limit      = UINT64_MAX;
759       sec_limit_depth = UINT_MAX;
760     }
761   else if ( ! strcmp( token, "byoyomi" ) )
762     {
763       token = strtok_r( NULL, str_delimiters, lasts );
764       if ( token == NULL )
765         {
766           str_error = str_bad_cmdline;
767           return -1;
768         }
769
770       l = strtol( token, &ptr, 0 );
771       if ( ptr == token || l > UINT_MAX || l < 1 )
772         {
773           str_error = str_bad_cmdline;
774           return -1;
775         }
776       
777       usi_byoyomi     = (unsigned int)l;
778       depth_limit     = PLY_MAX;
779       node_limit      = UINT64_MAX;
780       sec_limit_depth = UINT_MAX;
781     }
782   else {
783     str_error = str_bad_cmdline;
784     return -1;
785   }
786
787       
788   if ( get_elapsed( &time_turn_start ) < 0 ) { return -1; }
789
790   iret = com_turn_start( ptree, 0 );
791   if ( iret < 0 ) {
792     if ( str_error == str_no_legal_move ) { USIOut( "bestmove resign\n" ); }
793     else                                  { return -1; }
794   }
795   
796   return 1;
797 }
798
799
800 static int CONV
801 usi_posi( tree_t * restrict ptree, char **lasts )
802 {
803   const char *token;
804   char str_buf[7];
805   unsigned int move;
806     
807   AbortDifficultCommand;
808     
809   moves_ignore[0] = MOVE_NA;
810
811   token = strtok_r( NULL, str_delimiters, lasts );
812   if ( strcmp( token, "startpos" ) )
813     {
814       str_error = str_bad_cmdline;
815       return -1;
816     }
817     
818   if ( ini_game( ptree, &min_posi_no_handicap,
819                  flag_history, NULL, NULL ) < 0 ) { return -1; }
820     
821   token = strtok_r( NULL, str_delimiters, lasts );
822   if ( token == NULL ) { return 1; }
823
824   if ( strcmp( token, "moves" ) )
825     {
826       str_error = str_bad_cmdline;
827       return -1;
828     }
829     
830   for ( ;; )  {
831
832     token = strtok_r( NULL, str_delimiters, lasts );
833     if ( token == NULL ) { break; }
834       
835     if ( usi2csa( ptree, token, str_buf ) < 0 )            { return -1; }
836     if ( interpret_CSA_move( ptree, &move, str_buf ) < 0 ) { return -1; }
837     if ( make_move_root( ptree, move, ( flag_history | flag_time
838                                         | flag_rep
839                                         | flag_detect_hang ) ) < 0 )
840       {
841         return -1;
842       }
843   }
844     
845   if ( get_elapsed( &time_turn_start ) < 0 ) { return -1; }
846   return 1;
847 }
848
849 #endif
850
851
852 static int CONV cmd_move_now( void )
853 {
854   if ( game_status & flag_thinking ) { game_status |= flag_move_now; }
855
856   return 1;
857 }
858
859
860 static int CONV
861 cmd_usrmove( tree_t * restrict ptree, const char *str_move, char **lasts )
862 {
863   const char *str;
864   char *ptr;
865   long lelapsed;
866   unsigned int move;
867   int iret;
868
869   if ( game_status & mask_game_end )
870     {
871       str_error = str_game_ended;
872       return -2;
873     }
874   
875   if ( game_status & flag_thinking )
876     {
877       str_error = str_busy_think;
878       return -2;
879     }
880
881   str = strtok_r( NULL, str_delimiters, lasts );
882   if ( str == NULL ) { lelapsed = 0; }
883   else {
884     if ( *str != 'T' )
885       {
886         str_error = str_bad_cmdline;
887         return -2;
888       }
889     str += 1;
890     lelapsed = strtol( str, &ptr, 0 );
891     if ( ptr == str || lelapsed == LONG_MAX || lelapsed < 1 )
892       {
893         str_error = str_bad_cmdline;
894         return -2;
895       }
896   }
897
898   if ( game_status & ( flag_pondering | flag_puzzling ) )
899     {
900       int i;
901
902       for ( i = 0; i < ponder_nmove; i++ )
903         {
904           if ( ! strcmp( str_move, str_CSA_move(ponder_move_list[i]) ) )
905             {
906               break;
907             }
908         }
909       if ( i == ponder_nmove )
910         {
911 #if defined(CSA_LAN)
912           if ( sckt_csa != SCKT_NULL ) { AbortDifficultCommand; }
913 #endif
914
915 #if defined(CSASHOGI)
916           AbortDifficultCommand;
917 #else
918           str_error = str_illegal_move;
919           return -2;
920 #endif
921         }
922
923       if ( ( game_status & flag_puzzling )
924            || strcmp( str_move, str_CSA_move(ponder_move) ) )
925         {
926           ponder_move  = MOVE_PONDER_FAILED;
927           game_status |= flag_quit_ponder;
928           return 2;
929         }
930       else {
931         iret = update_time( Flip(root_turn) );
932         if ( iret < 0 ) { return iret; }
933         if ( lelapsed )
934           {
935             adjust_time( (unsigned int)lelapsed, Flip(root_turn) );
936           }
937
938         out_CSA( ptree, &record_game, ponder_move );
939
940         game_status      &= ~flag_pondering;
941         game_status      |= flag_thinking;
942 #ifdef XBOARD
943       if(!xboard_mode)
944 #endif
945         set_search_limit_time( root_turn );
946
947         OutCsaShogi( "info ponder end\n" );
948
949         str = str_time_symple( time_turn_start - time_start );
950         Out( "    %6s          MOVE PREDICTION HIT\n"
951              "  elapsed: b%u, w%u\n", str, sec_b_total, sec_w_total );
952         return 1;
953       }
954     }
955
956   iret = interpret_CSA_move( ptree, &move, str_move );
957   if ( iret < 0 ) { return iret; }
958   move_evasion_pchk = 0;
959   iret = make_move_root( ptree, move, ( flag_rep | flag_history | flag_time
960                                         | flag_detect_hang ) );
961   if ( iret < 0 )
962       {
963
964 #if defined(CSA_LAN)
965         if ( sckt_csa != SCKT_NULL )
966           {
967             if ( move_evasion_pchk )
968               {
969                 str  = str_CSA_move( move_evasion_pchk );
970                 iret = sckt_out( sckt_csa, "%c%s\n",
971                                  ach_turn[Flip(root_turn)], str );
972                 if ( iret < 0 ) { return iret; }
973               }
974             return cmd_suspend();
975           }
976 #endif
977
978         if ( move_evasion_pchk )
979           {
980             str = str_CSA_move( move_evasion_pchk );
981 #if defined(CSASHOGI)
982             OutCsaShogi( "move%s\n", str );
983             return cmd_suspend();
984 #else
985             snprintf( str_message, SIZE_MESSAGE, "perpetual check (%c%s)",
986                       ach_turn[Flip(root_turn)], str );
987             str_error = str_message;
988             return -2;
989 #endif
990           }
991
992         return iret;
993       }
994
995   if ( lelapsed ) { adjust_time( (unsigned int)lelapsed, Flip(root_turn) ); }
996   Out( "  elapsed: b%u, w%u\n", sec_b_total, sec_w_total );
997
998 #if defined(CSA_LAN)
999   if ( sckt_csa != SCKT_NULL && ( game_status & flag_mated ) )
1000     {
1001       iret = sckt_out( sckt_csa, "%%TORYO\n" );
1002       if ( iret < 0 ) { return iret; }
1003     }
1004 #endif
1005
1006   if ( ! ( game_status & mask_game_end ) )
1007     {
1008       iret = com_turn_start( ptree, 0 );
1009       if ( iret < 0 ) { return iret; }
1010     }
1011
1012   return 1;
1013 }
1014
1015
1016 static int CONV cmd_beep( char **lasts )
1017 {
1018   const char *str = strtok_r( NULL, str_delimiters, lasts );
1019   if ( str == NULL )
1020     {
1021       str_error = str_bad_cmdline;
1022       return -2;
1023     }
1024
1025   if      ( ! strcmp( str, str_on )  ) {  game_status &= ~flag_nobeep; }
1026   else if ( ! strcmp( str, str_off ) ) {  game_status |=  flag_nobeep; }
1027   else {
1028     str_error = str_bad_cmdline;
1029     return -2;
1030   }
1031
1032   return 1;
1033 }
1034
1035
1036 static int CONV cmd_peek( char **lasts )
1037 {
1038   const char *str = strtok_r( NULL, str_delimiters, lasts );
1039
1040   if ( str == NULL )
1041     {
1042       str_error = str_bad_cmdline;
1043       return -2;
1044     }
1045
1046   if      ( ! strcmp( str, str_on )  ) {  game_status &= ~flag_nopeek; }
1047   else if ( ! strcmp( str, str_off ) ) {  game_status |=  flag_nopeek; }
1048   else {
1049     str_error = str_bad_cmdline;
1050     return -2;
1051   }
1052
1053   return 1;
1054 }
1055
1056
1057 static int CONV cmd_stdout( char **lasts )
1058 {
1059   const char *str = strtok_r( NULL, str_delimiters, lasts );
1060
1061   if ( str == NULL )
1062     {
1063       str_error = str_bad_cmdline;
1064       return -2;
1065     }
1066
1067   if      ( ! strcmp( str, str_on )  ) {  game_status &= ~flag_nostdout; }
1068   else if ( ! strcmp( str, str_off ) ) {  game_status |=  flag_nostdout; }
1069   else {
1070     str_error = str_bad_cmdline;
1071     return -2;
1072   }
1073
1074   return 1;
1075 }
1076
1077
1078 static int CONV cmd_newlog( char **lasts )
1079 {
1080   const char *str = strtok_r( NULL, str_delimiters, lasts );
1081
1082   if ( str == NULL )
1083     {
1084       str_error = str_bad_cmdline;
1085       return -2;
1086     }
1087
1088   if      ( ! strcmp( str, str_on )  ) { game_status &= ~flag_nonewlog; }
1089   else if ( ! strcmp( str, str_off ) ) { game_status |=  flag_nonewlog; }
1090   else {
1091     str_error = str_bad_cmdline;
1092     return -2;
1093   }
1094
1095   return 1;
1096 }
1097
1098
1099 static int CONV cmd_ponder( char **lasts )
1100 {
1101   const char *str = strtok_r( NULL, str_delimiters, lasts );
1102
1103   if ( str == NULL )
1104     {
1105       str_error = str_bad_cmdline;
1106       return -2;
1107     }
1108
1109   if      ( ! strcmp( str, str_on )  ) { game_status &= ~flag_noponder; }
1110   else if ( ! strcmp( str, str_off ) )
1111     {
1112       if ( game_status & ( flag_pondering | flag_puzzling ) )
1113         {
1114           game_status |= flag_quit_ponder;
1115         }
1116       game_status |= flag_noponder;
1117     }
1118   else {
1119     str_error = str_bad_cmdline;
1120     return -2;
1121   }
1122
1123   return 1;
1124 }
1125
1126
1127 #if ! defined(NO_STDOUT)
1128 static int CONV cmd_stress( char **lasts )
1129 {
1130   const char *str = strtok_r( NULL, str_delimiters, lasts );
1131
1132   if ( str == NULL )
1133     {
1134       str_error = str_bad_cmdline;
1135       return -2;
1136     }
1137
1138   if      ( ! strcmp( str, str_on  ) ) { game_status &= ~flag_nostress; }
1139   else if ( ! strcmp( str, str_off ) ) { game_status |= flag_nostress; }
1140   else {
1141     str_error = str_bad_cmdline;
1142     return -2;
1143   }
1144
1145   return 1;
1146 }
1147 #endif
1148
1149
1150 static int CONV
1151 #if defined(MINIMUM)
1152 cmd_book( char **lasts )
1153 #else
1154 cmd_book( tree_t * restrict ptree, char **lasts )
1155 #endif
1156 {
1157   const char *str = strtok_r( NULL, str_delimiters, lasts );
1158   int iret = 1;
1159
1160   if ( str == NULL )
1161     {
1162       str_error = str_bad_cmdline;
1163       return -2;
1164     }
1165   if      ( ! strcmp( str, str_on ) )   { iret = book_on(); }
1166   else if ( ! strcmp( str, str_off ) )  { iret = book_off(); }
1167   else if ( ! strcmp( str, "narrow" ) ) { game_status |= flag_narrow_book; }
1168   else if ( ! strcmp( str, "wide" ) )   { game_status &= ~flag_narrow_book; }
1169 #if ! defined(MINIMUM)
1170   else if ( ! strcmp( str, "create" ) )
1171     {
1172       AbortDifficultCommand;
1173
1174       iret = book_create( ptree );
1175       if ( iret < 0 ) { return iret; }
1176
1177       iret = ini_game( ptree, &min_posi_no_handicap, flag_history,
1178                        NULL, NULL );
1179       if ( iret < 0 ) { return iret; }
1180
1181       iret = get_elapsed( &time_turn_start );
1182     }
1183 #endif
1184   else {
1185     str_error = str_bad_cmdline;
1186     iret = -2;
1187   }
1188
1189   return iret;
1190 }
1191
1192
1193 static int CONV cmd_display( tree_t * restrict ptree, char **lasts )
1194 {
1195   const char *str = strtok_r( NULL, str_delimiters, lasts );
1196   char *ptr;
1197   long l;
1198   int iret;
1199
1200   if ( str != NULL )
1201     {
1202       l = strtol( str, &ptr, 0 );
1203       if ( ptr == str )
1204         {
1205           str_error = str_bad_cmdline;
1206           return -2;
1207         }
1208       if      ( l == 1 ) { game_status &= ~flag_reverse; }
1209       else if ( l == 2 ) { game_status |= flag_reverse; }
1210       else {
1211         str_error = str_bad_cmdline;
1212         return -2;
1213       }
1214     }
1215   
1216   Out( "\n" );
1217   iret = out_board( ptree, stdout, 0, 0 );
1218   if ( iret < 0 ) { return iret; }
1219 #if ! defined(NO_LOGGING)
1220   iret = out_board( ptree, pf_log, 0, 0 );
1221   if ( iret < 0 ) { return iret; }
1222 #endif
1223   Out( "\n" );
1224
1225   return 1;
1226 }
1227
1228
1229 static int CONV cmd_ping( void )
1230 {
1231   OutCsaShogi( "pong\n" );
1232   Out( "pong\n" );
1233   return 1;
1234 }
1235
1236
1237 static int CONV cmd_hash( char **lasts )
1238 {
1239   const char *str = strtok_r( NULL, str_delimiters, lasts );
1240   char *ptr;
1241   long l;
1242
1243   if ( str == NULL )
1244     {
1245       str_error = str_bad_cmdline;
1246       return -2;
1247     }
1248
1249   l = strtol( str, &ptr, 0 );
1250   if ( ptr == str || l == LONG_MAX || l < 1 || l > 31 )
1251     {
1252       str_error = str_bad_cmdline;
1253       return -2;
1254     }
1255   
1256   AbortDifficultCommand;
1257   
1258   log2_ntrans_table = (int)l;
1259   memory_free( (void *)ptrans_table_orig );
1260   return ini_trans_table();
1261 }
1262
1263
1264 static int CONV cmd_limit( char **lasts )
1265 {
1266   const char *str = strtok_r( NULL, str_delimiters, lasts );
1267   char *ptr;
1268   long l1, l2, l3;
1269
1270   if ( str == NULL )
1271     {
1272       str_error = str_bad_cmdline;
1273       return -2;
1274     }
1275
1276   AbortDifficultCommand;
1277
1278   if ( ! strcmp( str, "depth" ) )
1279     {
1280       str = strtok_r( NULL, str_delimiters, lasts );
1281       if ( str == NULL )
1282         {
1283           str_error = str_bad_cmdline;
1284           return -2;
1285         }
1286       l1 = strtol( str, &ptr, 0 );
1287       if ( ptr == str || l1 == LONG_MAX || l1 < 1 )
1288         {
1289           str_error = str_bad_cmdline;
1290           return -2;
1291         }
1292       sec_limit_up = UINT_MAX;
1293       node_limit   = UINT64_MAX;
1294       depth_limit  = (int)l1;
1295     }
1296   else if ( ! strcmp( str, "nodes" ) )
1297     {
1298       str = strtok_r( NULL, str_delimiters, lasts );
1299       if ( str == NULL )
1300         {
1301           str_error = str_bad_cmdline;
1302           return -2;
1303         }
1304       l1 = strtol( str, &ptr, 0 );
1305       if ( ptr == str || l1 == LONG_MAX || l1 < 1 )
1306         {
1307           str_error = str_bad_cmdline;
1308           return -2;
1309         }
1310       sec_limit_up = UINT_MAX;
1311       depth_limit  = PLY_MAX;
1312       node_limit   = (uint64_t)l1;
1313     }
1314   else if ( ! strcmp( str, "time" ) )
1315     {
1316       str = strtok_r( NULL, str_delimiters, lasts );
1317       if ( str == NULL )
1318         {
1319           str_error = str_bad_cmdline;
1320           return -2;
1321         }
1322
1323       if ( ! strcmp( str, "extendable" ) )
1324         {
1325           game_status |= flag_time_extendable;
1326         }
1327       else if ( ! strcmp( str, "strict" ) )
1328         {
1329           game_status &= ~flag_time_extendable;
1330         }
1331       else {
1332         l1 = strtol( str, &ptr, 0 );
1333         if ( ptr == str || l1 == LONG_MAX || l1 < 0 )
1334           {
1335             str_error = str_bad_cmdline;
1336             return -2;
1337           }
1338
1339         str = strtok_r( NULL, str_delimiters, lasts );
1340         if ( str == NULL )
1341           {
1342             str_error = str_bad_cmdline;
1343             return -2;
1344           }
1345         l2 = strtol( str, &ptr, 0 );
1346         if ( ptr == str || l2 == LONG_MAX || l2 < 0 )
1347           {
1348             str_error = str_bad_cmdline;
1349             return -2;
1350           }
1351
1352         str = strtok_r( NULL, str_delimiters, lasts );
1353         if ( ! str ) { l3 = -1; }
1354         else {
1355           l3 = strtol( str, &ptr, 0 );
1356           if ( ptr == str || l3 >= PLY_MAX || l3 < -1 )
1357             {
1358               str_error = str_bad_cmdline;
1359               return -2;
1360             }
1361         }
1362
1363         if ( ! ( l1 | l2 ) ) { l2 = 1; }
1364
1365         depth_limit  = PLY_MAX;
1366         node_limit   = UINT64_MAX;
1367         sec_limit    = (unsigned int)l1 * 60U;
1368         sec_limit_up = (unsigned int)l2;
1369         if ( l3 == -1 ) { sec_limit_depth = UINT_MAX; }
1370         else            { sec_limit_depth = (unsigned int)l3; }
1371       }
1372     }
1373   else {
1374     str_error = str_bad_cmdline;
1375     return -2;
1376   }
1377
1378   return 1;
1379 }
1380
1381
1382 static int CONV
1383 cmd_read( tree_t * restrict ptree, char **lasts )
1384 {
1385   const char *str1 = strtok_r( NULL, str_delimiters, lasts );
1386   const char *str2 = strtok_r( NULL, str_delimiters, lasts );
1387   const char *str3 = strtok_r( NULL, str_delimiters, lasts );
1388   const char *str_tmp;
1389   FILE *pf_src, *pf_dest;
1390   char str_file[SIZE_FILENAME];
1391   char *ptr;
1392   unsigned int moves;
1393   long l;
1394   int iret, flag, c;
1395
1396   flag    = flag_history | flag_rep | flag_detect_hang;
1397   moves   = UINT_MAX;
1398   str_tmp = NULL;
1399
1400   if ( str1 == NULL )
1401     {
1402       str_error = str_bad_cmdline;
1403       return -2;
1404     }
1405
1406   if ( str2 != NULL )
1407     {
1408       if ( ! strcmp( str2, "t" ) ) { flag |= flag_time; }
1409       else if ( strcmp( str2, "nil" ) )
1410         {
1411           str_error = str_bad_cmdline;
1412           return -2;
1413         }
1414     }
1415
1416   if ( str3 != NULL )
1417     {
1418       l = strtol( str3, &ptr, 0 );
1419       if ( ptr == str3 || l == LONG_MAX || l < 1 )
1420         {
1421           str_error = str_bad_cmdline;
1422           return -2;
1423         }
1424       moves = (unsigned int)l - 1U;
1425     }
1426
1427   AbortDifficultCommand;
1428
1429   if ( ! strcmp( str1, "." ) )
1430     {
1431       str_tmp = "game.cs_";
1432
1433 #if defined(NO_LOGGING)
1434       strncpy( str_file, "game.csa", SIZE_FILENAME-1 );
1435 #else
1436       snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
1437                 str_dir_logs, record_num );
1438 #endif
1439       pf_dest = file_open( str_tmp, "w" );
1440       if ( pf_dest == NULL ) { return -2; }
1441
1442       pf_src = file_open( str_file, "r" );
1443       if ( pf_src == NULL )
1444         {
1445           file_close( pf_dest );
1446           return -2;
1447         }
1448
1449       while ( ( c = getc(pf_src) ) != EOF ) { putc( c, pf_dest ); }
1450
1451       iret = file_close( pf_src );
1452       if ( iret < 0 )
1453         {
1454           file_close( pf_dest );
1455           return iret;
1456         }
1457
1458       iret = file_close( pf_dest );
1459       if ( iret < 0 ) { return iret; }
1460
1461       flag |= flag_time;
1462       str1  = str_tmp;
1463     }
1464
1465   iret = read_record( ptree, str1, moves, flag );
1466   if ( iret < 0 ) { return iret; }
1467
1468   iret = get_elapsed( &time_turn_start );
1469   if ( iret < 0 ) { return iret; }
1470
1471   if ( str_tmp && remove( str_tmp ) )
1472     {
1473       out_warning( "remove() failed." );
1474       return -2;
1475     }
1476
1477   return 1;
1478 }
1479
1480
1481 static int CONV cmd_resign( tree_t * restrict ptree, char **lasts )
1482 {
1483   const char *str = strtok_r( NULL, str_delimiters, lasts );
1484   char *ptr;
1485   long l;
1486
1487   if ( str == NULL || *str == 'T' )
1488     {
1489       AbortDifficultCommand;
1490
1491       if ( game_status & mask_game_end ) { return 1; }
1492
1493       game_status |= flag_resigned;
1494       update_time( root_turn );
1495       out_CSA( ptree, &record_game, MOVE_RESIGN );
1496     }
1497   else {
1498     l = strtol( str, &ptr, 0 );
1499     if ( ptr == str || l == LONG_MAX || l < MT_CAP_PAWN )
1500       {
1501         str_error = str_bad_cmdline;
1502         return -2;
1503       }
1504     resign_threshold = (int)l;
1505   }
1506
1507   return 1;
1508 }
1509
1510
1511 static int CONV cmd_move( tree_t * restrict ptree, char **lasts )
1512 {
1513   const char *str = strtok_r( NULL, str_delimiters, lasts );
1514   char *ptr;
1515   long l;
1516   unsigned int move;
1517   int iret, i;
1518
1519   if ( game_status & mask_game_end )
1520     {
1521       str_error = str_game_ended;
1522       return -2;
1523     }
1524   
1525   AbortDifficultCommand;
1526
1527   if ( str == NULL )
1528     {
1529       if ( analyze_mode ) // [HGM] analyze: in analysis mode we cannot set the engine thinking (but perhaps play PV move?)
1530           {
1531             str_error = str_bad_cmdline;
1532             return -2;
1533           }
1534
1535       iret = get_elapsed( &time_turn_start );
1536       if ( iret < 0 ) { return iret; }
1537       
1538       return com_turn_start( ptree, 0 );
1539     }
1540
1541   l = strtol( str, &ptr, 0 );
1542   if ( str != ptr && l != LONG_MAX && l >= 1 && *ptr == '\0' )
1543     {
1544       if ( analyze_mode ) // [HGM] analyze: in analysis mode we cannot set the engine thinking
1545           {
1546             str_error = str_bad_cmdline;
1547             return -2;
1548           }
1549
1550       for ( i = 0; i < l; i += 1 )
1551         {
1552           if ( game_status & ( flag_move_now | mask_game_end ) ) { break; }
1553
1554           iret = get_elapsed( &time_turn_start );
1555           if ( iret < 0 ) { return iret; }
1556         
1557           iret = com_turn_start( ptree, 0 );
1558           if ( iret < 0 ) { return iret; }
1559         }
1560
1561       return 1;
1562     }
1563
1564   do {
1565     iret = interpret_CSA_move( ptree, &move, str );
1566     if ( iret < 0 ) { return iret; }
1567     
1568     iret = get_elapsed( &time_turn_start );
1569     if ( iret < 0 ) { return iret; }
1570     
1571     iret = make_move_root( ptree, move,
1572                            ( flag_history | flag_time | flag_rep
1573                              | flag_detect_hang ) );
1574     if ( iret < 0 ) { return iret; }
1575     
1576     str = strtok_r( NULL, str_delimiters, lasts );
1577
1578   } while ( str != NULL );
1579
1580   moves_ignore[0] = MOVE_NA; // [HGM] exclude: exclude list cleared for new position
1581   if ( analyze_mode ) return do_analyze ( ptree ); // [HGM] analyze: analysis should continue after feeding moves
1582   
1583   return 1;
1584 }
1585
1586
1587 static int CONV cmd_new( tree_t * restrict ptree, char **lasts )
1588 {
1589   const char *str1 = strtok_r( NULL, str_delimiters, lasts );
1590   const char *str2 = strtok_r( NULL, str_delimiters, lasts );
1591   const min_posi_t *pmp;
1592   min_posi_t min_posi;
1593   int iret;
1594
1595   AbortDifficultCommand;
1596
1597   start_pos = *lasts; move_ptr = 0; // [HGM] undo: remember start position
1598   moves_ignore[0] = MOVE_NA; // [HGM] exclude: exclude list cleared for new position
1599
1600   if ( str1 != NULL )
1601     {
1602       strncpy(start_data, str1, 511); // [HGM] undo: remember start position
1603       memset( &min_posi.asquare, empty, nsquare );
1604       min_posi.hand_black = min_posi.hand_white = 0;
1605       iret = read_board_rep1( str1, &min_posi );
1606       if ( iret < 0 ) { return iret; }
1607
1608       if ( str2 != NULL )
1609         {
1610           if      ( ! strcmp( str2, "-" ) ) { min_posi.turn_to_move = white; }
1611           else if ( ! strcmp( str2, "+" ) ) { min_posi.turn_to_move = black; }
1612           else {
1613             str_error = str_bad_cmdline;
1614             return -2;
1615           }
1616         }
1617       else { min_posi.turn_to_move = black; }
1618
1619       pmp = &min_posi;
1620     }
1621   else { pmp = &min_posi_no_handicap; }
1622
1623   iret = ini_game( ptree, pmp, flag_history, NULL, NULL );
1624   if ( iret < 0 ) { return iret; }
1625
1626   return get_elapsed( &time_turn_start );
1627 }
1628
1629
1630 static int CONV cmd_outmove( tree_t * restrict ptree )
1631 {
1632   const char *str_move;
1633   char buffer[256];
1634   unsigned int move_list[ MAX_LEGAL_MOVES ];
1635   int i, c, n;
1636
1637   AbortDifficultCommand;
1638
1639   if ( game_status & mask_game_end )
1640     {
1641       Out( "NO LEGAL MOVE\n" );
1642       DFPNOut( "NO LEGAL MOVE\n" );
1643       return 1;
1644     }
1645
1646   n = gen_legal_moves( ptree, move_list, 0 );
1647
1648   buffer[0]='\0';
1649   for ( c = i = 0; i < n; i += 1 )
1650     {
1651       str_move = str_CSA_move(move_list[i]);
1652
1653       if ( i && ( i % 10 ) == 0 )
1654         {
1655           Out( "%s\n", buffer );
1656           DFPNOut( "%s ", buffer );
1657           memcpy( buffer, str_move, 6 );
1658           c = 6;
1659         }
1660       else if ( i )
1661         {
1662           buffer[c] = ' ';
1663           memcpy( buffer + c + 1, str_move, 6 );
1664           c += 7;
1665         }
1666       else {
1667         memcpy( buffer + c, str_move, 6 );
1668         c += 6;
1669       }
1670       buffer[c] = '\0';
1671     }
1672   Out( "%s\n", buffer );
1673   DFPNOut( "%s\n", buffer );
1674
1675   return 1;
1676 }
1677
1678
1679 static int CONV cmd_problem( tree_t * restrict ptree, char **lasts )
1680 {
1681   const char *str = strtok_r( NULL, str_delimiters, lasts );
1682   char *ptr;
1683   long l;
1684   unsigned int nposition;
1685   int iret;
1686 #if defined(DFPN)
1687   int is_mate;
1688 #endif
1689
1690   AbortDifficultCommand;
1691
1692
1693 #if defined(DFPN)
1694   is_mate = 0;
1695   if ( str != NULL && ! strcmp( str, "mate" ) )
1696     {
1697       is_mate = 1;
1698       str     = strtok_r( NULL, str_delimiters, lasts );
1699     }
1700 #endif
1701
1702   if ( str != NULL )
1703     {
1704       l = strtol( str, &ptr, 0 );
1705       if ( ptr == str || l == LONG_MAX || l < 1 )
1706         {
1707           str_error = str_bad_cmdline;
1708           return -2;
1709         }
1710       nposition = (unsigned int)l;
1711     }
1712   else { nposition = UINT_MAX; }
1713
1714   
1715   iret = record_open( &record_problems, "problem.csa", mode_read, NULL, NULL );
1716   if ( iret < 0 ) { return iret; }
1717
1718 #if defined(DFPN)
1719   iret = is_mate ? solve_mate_problems( ptree, nposition )
1720                  : solve_problems( ptree, nposition );
1721 #else
1722   iret = solve_problems( ptree, nposition );
1723 #endif
1724
1725   if ( iret < 0 )
1726     {
1727       record_close( &record_problems );
1728       return iret;
1729     }
1730
1731   iret = record_close( &record_problems );
1732   if ( iret < 0 ) { return iret; }
1733
1734   return get_elapsed( &time_turn_start );
1735 }
1736
1737
1738 static int CONV cmd_quit( void )
1739 {
1740   game_status |= flag_quit;
1741   return 1;
1742 }
1743
1744
1745 static int CONV cmd_suspend( void )
1746 {
1747   if ( game_status & ( flag_pondering | flag_puzzling ) )
1748     {
1749       game_status |= flag_quit_ponder;
1750       return 2;
1751     }
1752   
1753   game_status |= flag_suspend;
1754   return 1;
1755 }
1756
1757
1758 static int CONV cmd_time( char **lasts )
1759 {
1760   const char *str = strtok_r( NULL, str_delimiters, lasts );
1761   char *ptr;
1762
1763   if ( str == NULL )
1764     {
1765       str_error = str_bad_cmdline;
1766       return -2;
1767     }
1768   else if ( ! strcmp( str, "response" ) )
1769     {
1770       long l;
1771       str = strtok_r( NULL, str_delimiters, lasts );
1772       if ( str == NULL )
1773         {
1774           str_error = str_bad_cmdline;
1775           return -2;
1776         }
1777       l = strtol( str, &ptr, 0 );
1778       if ( ptr == str || l == LONG_MAX || l < 0 || l > 1000 )
1779         {
1780           str_error = str_bad_cmdline;
1781           return -2;
1782         }
1783       time_response = (unsigned int)l;
1784       return 1;
1785     }
1786   else if ( ! strcmp( str, "remain" ) )
1787     {
1788       long l1, l2;
1789       
1790       str = strtok_r( NULL, str_delimiters, lasts );
1791       if ( str == NULL )
1792         {
1793           str_error = str_bad_cmdline;
1794           return -2;
1795         }
1796       l1 = strtol( str, &ptr, 0 );
1797       if ( ptr == str || l1 == LONG_MAX || l1 < 0 )
1798         {
1799           str_error = str_bad_cmdline;
1800           return -2;
1801         }
1802
1803       str = strtok_r( NULL, str_delimiters, lasts );
1804       if ( str == NULL )
1805         {
1806           str_error = str_bad_cmdline;
1807           return -2;
1808         }
1809       l2 = strtol( str, &ptr, 0 );
1810       if ( ptr == str || l2 == LONG_MAX || l2 < 0 )
1811         {
1812           str_error = str_bad_cmdline;
1813           return -2;
1814         }
1815
1816       if ( sec_limit_up == UINT_MAX )
1817         {
1818           str_error = str_bad_cmdline;
1819           return -2;
1820         }
1821
1822       return reset_time( (unsigned int)l1, (unsigned int)l2 );
1823     }
1824
1825   str_error = str_bad_cmdline;
1826   return -2;
1827 }
1828
1829
1830 #if !defined(MINIMUM)
1831 /* learn (ini|no-ini) steps games iterations tlp1 tlp2 */
1832 static int CONV cmd_learn( tree_t * restrict ptree, char **lasts )
1833 {
1834   const char *str1 = strtok_r( NULL, str_delimiters, lasts );
1835   const char *str2 = strtok_r( NULL, str_delimiters, lasts );
1836   const char *str3 = strtok_r( NULL, str_delimiters, lasts );
1837   const char *str4 = strtok_r( NULL, str_delimiters, lasts );
1838 #  if defined(TLP)
1839   const char *str5 = strtok_r( NULL, str_delimiters, lasts );
1840   const char *str6 = strtok_r( NULL, str_delimiters, lasts );
1841 #  endif
1842   char *ptr;
1843   long l;
1844   unsigned int max_games;
1845   int is_ini, nsteps, max_iterations, nworker1, nworker2, iret;
1846
1847   if ( str1 == NULL )
1848     {
1849       str_error = str_bad_cmdline;
1850       return -2;
1851     }
1852   if      ( ! strcmp( str1, "ini" ) )    { is_ini = 1; }
1853   else if ( ! strcmp( str1, "no-ini" ) ) { is_ini = 0; }
1854   else {
1855     str_error = str_bad_cmdline;
1856     return -2;
1857   }
1858
1859   max_games      = UINT_MAX;
1860   max_iterations = INT_MAX;
1861   nworker1 = nworker2 = nsteps = 1;
1862
1863   if ( str2 != NULL )
1864     {
1865       l = strtol( str2, &ptr, 0 );
1866       if ( ptr == str2 || l == LONG_MAX || l < 1 )
1867         {
1868           str_error = str_bad_cmdline;
1869           return -2;
1870         }
1871       nsteps = (int)l;
1872     }
1873
1874   if ( str3 != NULL )
1875     {
1876       l = strtol( str3, &ptr, 0 );
1877       if ( ptr == str3 || l == LONG_MAX || l == LONG_MIN )
1878         {
1879           str_error = str_bad_cmdline;
1880           return -2;
1881         }
1882       if ( l > 0 ) { max_games = (unsigned int)l; }
1883     }
1884
1885   if ( str4 != NULL )
1886     {
1887       l = strtol( str4, &ptr, 0 );
1888       if ( ptr == str4 || l == LONG_MAX || l == LONG_MIN )
1889         {
1890           str_error = str_bad_cmdline;
1891           return -2;
1892         }
1893       if ( l > 0 ) { max_iterations = (int)l; }
1894     }
1895
1896 #  if defined(TLP)
1897   if ( str5 != NULL )
1898     {
1899       l = strtol( str5, &ptr, 0 );
1900       if ( ptr == str5 || l > TLP_MAX_THREADS || l < 1 )
1901         {
1902           str_error = str_bad_cmdline;
1903           return -2;
1904         }
1905       nworker1 = (int)l;
1906     }
1907
1908   if ( str6 != NULL )
1909     {
1910       l = strtol( str6, &ptr, 0 );
1911       if ( ptr == str6 || l > TLP_MAX_THREADS || l < 1 )
1912         {
1913           str_error = str_bad_cmdline;
1914           return -2;
1915         }
1916       nworker2 = (int)l;
1917     }
1918 #  endif
1919
1920   AbortDifficultCommand;
1921
1922   log2_ntrans_table = 12;
1923
1924   memory_free( (void *)ptrans_table_orig );
1925
1926   iret = ini_trans_table();
1927   if ( iret < 0 ) { return iret; }
1928
1929   iret = learn( ptree, is_ini, nsteps, max_games, max_iterations,
1930                 nworker1, nworker2 );
1931   if ( iret < 0 ) { return -1; }
1932
1933   iret = ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL );
1934   if ( iret < 0 ) { return -1; }
1935
1936   iret = get_elapsed( &time_turn_start );
1937   if ( iret < 0 ) { return iret; }
1938
1939   return 1;
1940 }
1941 #endif /* MINIMUM */
1942
1943
1944 #if defined(MPV)
1945 static int CONV cmd_mpv( tree_t * restrict ptree, char **lasts )
1946 {
1947   const char *str = strtok_r( NULL, str_delimiters, lasts );
1948   char *ptr;
1949   long l;
1950
1951   if ( str == NULL )
1952     {
1953       str_error = str_bad_cmdline;
1954       return -2;
1955     }
1956   else if ( ! strcmp( str, "num" ) )
1957     {
1958       str = strtok_r( NULL, str_delimiters, lasts );
1959       if ( str == NULL )
1960         {
1961           str_error = str_bad_cmdline;
1962           return -2;
1963         }
1964       l = strtol( str, &ptr, 0 );
1965       if ( ptr == str || l == LONG_MAX || l < 1 || l > MPV_MAX_PV )
1966         {
1967           str_error = str_bad_cmdline;
1968           return -2;
1969         }
1970
1971       AbortDifficultCommand;
1972
1973       mpv_num = (int)l;
1974
1975       if ( analyze_mode ) return do_analyze ( ptree ); // [HGM] analyze: analysis should continue changing num
1976
1977       return 1;
1978     }
1979   else if ( ! strcmp( str, "width" ) )
1980     {
1981       str = strtok_r( NULL, str_delimiters, lasts );
1982       if ( str == NULL )
1983         {
1984           str_error = str_bad_cmdline;
1985           return -2;
1986         }
1987       l = strtol( str, &ptr, 0 );
1988       if ( ptr == str || l == LONG_MAX || l < MT_CAP_PAWN )
1989         {
1990           str_error = str_bad_cmdline;
1991           return -2;
1992         }
1993
1994       AbortDifficultCommand;
1995
1996       mpv_width = (int)l;
1997
1998       if ( analyze_mode ) return do_analyze ( ptree ); // [HGM] analyze: analysis should continue after changing width
1999
2000       return 1;
2001     }
2002
2003   str_error = str_bad_cmdline;
2004   return -2;
2005 }
2006 #endif
2007
2008
2009 #if defined(DFPN)
2010 static int CONV cmd_dfpn( tree_t * restrict ptree, char **lasts )
2011 {
2012   const char *str = strtok_r( NULL, str_delimiters, lasts );
2013
2014   if ( str == NULL )
2015     {
2016       str_error = str_bad_cmdline;
2017       return -2;
2018     }
2019   else if ( ! strcmp( str, "hash" ) )
2020     {
2021       char *ptr;
2022       long l;
2023
2024       str = strtok_r( NULL, str_delimiters, lasts );
2025       if ( str == NULL )
2026         {
2027           str_error = str_bad_cmdline;
2028           return -2;
2029         }
2030       l = strtol( str, &ptr, 0 );
2031       if ( ptr == str || l == LONG_MAX || l < 1 )
2032         {
2033           str_error = str_bad_cmdline;
2034           return -2;
2035         }
2036
2037       AbortDifficultCommand;
2038
2039       dfpn_hash_log2 = (unsigned int)l;
2040       return dfpn_ini_hash();
2041     }
2042   else if ( ! strcmp( str, "go" ) )
2043     {
2044       AbortDifficultCommand;
2045
2046       return dfpn( ptree, root_turn, 1 );
2047     }
2048   else if ( ! strcmp( str, "connect" ) )
2049     {
2050       char str_addr[256];
2051       char str_id[256];
2052       char *ptr;
2053       long l;
2054       int port;
2055
2056       str = strtok_r( NULL, str_delimiters, lasts );
2057       if ( ! str || ! strcmp( str, "." ) ) { str = "127.0.0.1"; }
2058       strncpy( str_addr, str, 255 );
2059       str_addr[255] = '\0';
2060
2061       str = strtok_r( NULL, str_delimiters, lasts );
2062       if ( ! str || ! strcmp( str, "." ) ) { str = "4083"; }
2063       l = strtol( str, &ptr, 0 );
2064       if ( ptr == str || l == LONG_MAX || l < 0 || l > USHRT_MAX )
2065         {
2066           str_error = str_bad_cmdline;
2067           return -2;
2068         }
2069       port = (int)l;
2070
2071       str = strtok_r( NULL, str_delimiters, lasts );
2072       if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza1"; }
2073       strncpy( str_id, str, 255 );
2074       str_id[255] = '\0';
2075
2076       AbortDifficultCommand;
2077       
2078       dfpn_sckt = sckt_connect( str_addr, port );
2079       if ( dfpn_sckt == SCKT_NULL ) { return -2; }
2080
2081       str_buffer_cmdline[0] = '\0';
2082       DFPNOut( "Worker: %s\n", str_id );
2083
2084       return 1;
2085     }
2086
2087   str_error = str_bad_cmdline;
2088   return -2;
2089 }
2090 #endif
2091
2092
2093 #if defined(TLP)
2094 static int CONV cmd_thread( char **lasts )
2095 {
2096   const char *str = strtok_r( NULL, str_delimiters, lasts );
2097
2098   if ( str == NULL )
2099     {
2100       str_error = str_bad_cmdline;
2101       return -2;
2102     }
2103   else if ( ! strcmp( str, "num" ) )
2104     {
2105       char *ptr;
2106       long l;
2107
2108       str = strtok_r( NULL, str_delimiters, lasts );
2109       if ( str == NULL )
2110         {
2111           str_error = str_bad_cmdline;
2112           return -2;
2113         }
2114       l = strtol( str, &ptr, 0 );
2115       if ( ptr == str || l == LONG_MAX || l < 1 || l > TLP_MAX_THREADS )
2116         {
2117           str_error = str_bad_cmdline;
2118           return -2;
2119         }
2120
2121       TlpEnd();
2122
2123       tlp_max = (int)l;
2124
2125       if ( game_status & ( flag_thinking | flag_pondering | flag_puzzling ) )
2126         {
2127           return tlp_start();
2128         }
2129       return 1;
2130     }
2131
2132   str_error = str_bad_cmdline;
2133   return -2;
2134 }
2135 #endif
2136
2137
2138 #if defined(DFPN_CLIENT)
2139 static int CONV cmd_dfpn_client( tree_t * restrict ptree, char **lasts )
2140 {
2141   const char *str;
2142   char *ptr;
2143   int iret;
2144
2145   AbortDifficultCommand;
2146
2147   str = strtok_r( NULL, str_delimiters, lasts );
2148   if ( ! str || ! strcmp( str, "." ) ) { str = "127.0.0.1"; }
2149   strncpy( dfpn_client_str_addr, str, 255 );
2150   dfpn_client_str_addr[255] = '\0';
2151
2152   str = strtok_r( NULL, str_delimiters, lasts );
2153   if ( ! str || ! strcmp( str, "." ) ) { str = "4083"; }
2154   dfpn_client_port = strtol( str, &ptr, 0 );
2155   if ( ptr == str || dfpn_client_port == LONG_MAX || dfpn_client_port < 0
2156        || dfpn_client_port > USHRT_MAX )
2157     {
2158       str_error = str_bad_cmdline;
2159       return -2;
2160     }
2161
2162   Out( "DFPN Server: %s %d\n", dfpn_client_str_addr, dfpn_client_port );
2163
2164   iret = ini_game( ptree, &min_posi_no_handicap, flag_history, NULL, NULL );
2165   if ( iret < 0 ) { return iret; }
2166
2167   if ( dfpn_client_sckt == SCKT_NULL )
2168     {
2169       str_error = "Check network status.";
2170       return -1;
2171     }
2172
2173   return get_elapsed( &time_turn_start );
2174 }
2175 #endif
2176
2177
2178 #if defined(CSA_LAN)
2179 static int CONV cmd_connect( tree_t * restrict ptree, char **lasts )
2180 {
2181   const char *str;
2182   char *ptr;
2183   long max_games;
2184
2185   str = strtok_r( NULL, str_delimiters, lasts );
2186   if ( ! str || ! strcmp( str, "." ) ) { str = "gserver.computer-shogi.org"; }
2187   strncpy( client_str_addr, str, 255 );
2188   client_str_addr[255] = '\0';
2189
2190   str = strtok_r( NULL, str_delimiters, lasts );
2191   if ( ! str || ! strcmp( str, "." ) ) { str = "4081"; }
2192   client_port = strtol( str, &ptr, 0 );
2193   if ( ptr == str || client_port == LONG_MAX || client_port < 0
2194        || client_port > USHRT_MAX )
2195     {
2196       str_error = str_bad_cmdline;
2197       return -2;
2198     }
2199
2200   str = strtok_r( NULL, str_delimiters, lasts );
2201   if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza_test"; }
2202   strncpy( client_str_id, str, 255 );
2203   client_str_id[255] = '\0';
2204
2205   str = strtok_r( NULL, " \t", lasts );
2206   if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza_test"; }
2207   strncpy( client_str_pwd, str, 255 );
2208   client_str_pwd[255] = '\0';
2209
2210   str = strtok_r( NULL, str_delimiters, lasts );
2211   if ( ! str || ! strcmp( str, "." ) ) { client_max_game = INT_MAX; }
2212   else {
2213     max_games = strtol( str, &ptr, 0 );
2214     if ( ptr == str || max_games == LONG_MAX || max_games < 1 )
2215     {
2216       str_error = str_bad_cmdline;
2217       return -2;
2218     }
2219     client_max_game = max_games;
2220   }
2221
2222   AbortDifficultCommand;
2223
2224   client_ngame          = 0;
2225
2226   return client_next_game( ptree, client_str_addr, (int)client_port );
2227 }
2228
2229
2230 static int CONV cmd_sendpv( char **lasts )
2231 {
2232   const char *str = strtok_r( NULL, str_delimiters, lasts );
2233
2234   if ( str == NULL )
2235     {
2236       str_error = str_bad_cmdline;
2237       return -2;
2238     }
2239
2240   if      ( ! strcmp( str, str_off ) ) {  game_status &= ~flag_sendpv; }
2241   else if ( ! strcmp( str, str_on ) )  {  game_status |=  flag_sendpv; }
2242   else {
2243     str_error = str_bad_cmdline;
2244     return -2;
2245   }
2246
2247   return 1;
2248 }
2249 #endif
2250
2251
2252 #if defined(MNJ_LAN)
2253 /* mnj sd seed addr port name factor stable_depth */
2254 static int CONV cmd_mnj( char **lasts )
2255 {
2256   char client_str_addr[256];
2257   char client_str_id[256];
2258   const char *str;
2259   char *ptr;
2260   unsigned int seed;
2261   long l;
2262   int client_port, sd;
2263   double factor;
2264
2265   str = strtok_r( NULL, str_delimiters, lasts );
2266   if ( ! str )
2267     {
2268       str_error = str_bad_cmdline;
2269       return -2;
2270     }
2271   l = strtol( str, &ptr, 0 );
2272   if ( ptr == str || l == LONG_MAX || l < 0 )
2273     {
2274       str_error = str_bad_cmdline;
2275       return -2;
2276     }
2277   sd = (int)l;
2278
2279
2280   str = strtok_r( NULL, str_delimiters, lasts );
2281   if ( ! str )
2282     {
2283       str_error = str_bad_cmdline;
2284       return -2;
2285     }
2286   l = strtol( str, &ptr, 0 );
2287   if ( ptr == str || l == LONG_MAX || l < 0 )
2288     {
2289       str_error = str_bad_cmdline;
2290       return -2;
2291     }
2292   seed = (unsigned int)l;
2293
2294
2295   str = strtok_r( NULL, str_delimiters, lasts );
2296   if ( ! str || ! strcmp( str, "." ) ) { str = "localhost"; }
2297   strncpy( client_str_addr, str, 255 );
2298   client_str_addr[255] = '\0';
2299
2300
2301   str = strtok_r( NULL, str_delimiters, lasts );
2302   if ( ! str || ! strcmp( str, "." ) ) { str = "4082"; }
2303   l = strtol( str, &ptr, 0 );
2304   if ( ptr == str || l == LONG_MAX || l < 0 || l > USHRT_MAX )
2305     {
2306       str_error = str_bad_cmdline;
2307       return -2;
2308     }
2309   client_port = (int)l;
2310
2311
2312   str = strtok_r( NULL, str_delimiters, lasts );
2313   if ( ! str || ! strcmp( str, "." ) ) { str = "bonanza1"; }
2314   strncpy( client_str_id, str, 255 );
2315   client_str_id[255] = '\0';
2316
2317   str = strtok_r( NULL, str_delimiters, lasts );
2318   if ( ! str || ! strcmp( str, "." ) ) { str = "1.0"; }
2319   factor = strtod( str, &ptr );
2320   if ( ptr == str || factor < 0.0 )
2321     {
2322       str_error = str_bad_cmdline;
2323       return -2;
2324     }
2325
2326   str = strtok_r( NULL, str_delimiters, lasts );
2327   if ( ! str || ! strcmp( str, "." ) ) { l = -1; }
2328   else {
2329     l = strtol( str, &ptr, 0 );
2330     if ( ptr == str || l == LONG_MAX )
2331       {
2332         str_error = str_bad_cmdline;
2333         return -2;
2334       }
2335   }
2336   if ( l <= 0 ) { mnj_depth_stable = INT_MAX; }
2337   else          { mnj_depth_stable = (int)l; }
2338
2339   AbortDifficultCommand;
2340
2341   resign_threshold  = 65535;
2342   game_status      |= ( flag_noponder | flag_noprompt );
2343   if ( mnj_reset_tbl( sd, seed ) < 0 ) { return -1; }
2344
2345   sckt_mnj = sckt_connect( client_str_addr, (int)client_port );
2346   if ( sckt_mnj == SCKT_NULL ) { return -2; }
2347
2348   str_buffer_cmdline[0] = '\0';
2349
2350   Out( "Sending my name %s", client_str_id );
2351   MnjOut( "%s %g final%s\n", client_str_id, factor,
2352           ( mnj_depth_stable == INT_MAX ) ? "" : " stable" );
2353
2354   return cmd_suspend();
2355 }
2356 #endif
2357
2358