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