Fix pondering in XBoard mode
[bonanza.git] / io.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdarg.h>
5 #include <errno.h>
6 #if defined(_WIN32)
7 #  include <io.h>
8 #  include <conio.h>
9 #else
10 #  include <sys/time.h>
11 #  include <sys/types.h>
12 #  include <unistd.h>
13 #endif
14 #include "shogi.h"
15
16 #if defined(_MSC_VER)
17 #  include <Share.h>
18 #  define fopen( file, mode ) _fsopen( file, mode, _SH_DENYNO )
19 #endif
20
21 #if defined(NO_STDOUT) || defined(WIN32_PIPE)
22 static int out_board0( FILE *pf, int piece, int i, int ito, int ifrom );
23 #  define OutBoard0(a,b,c,d,e,f) out_board0(a,b,c,d,e)
24 #else
25 static int out_board0( FILE *pf, int piece, int i, int ito, int ifrom,
26                        int is_promote );
27 #  define OutBoard0(a,b,c,d,e,f) out_board0(a,b,c,d,e,f)
28 #endif
29
30 static int check_input_buffer( void );
31 static int read_command( char **pstr_line_end );
32 static void out_hand( FILE *pf, unsigned int hand, const char *str_prefix );
33 static void out_hand0( FILE *pf, int n, const char *str_prefix,
34                        const char *str );
35
36 #if ! ( defined(NO_STDOUT) && defined(NO_LOGGING) )
37 void
38 out( const char *format, ... )
39 {
40   va_list arg;
41   if ( game_status & flag_quiet ) { return; }
42
43 #  if ! defined(NO_STDOUT)
44   va_start( arg, format );
45   vprintf( format, arg );
46   va_end( arg );
47   fflush( stdout );
48 #  endif
49
50 #  if ! defined(NO_LOGGING)
51   if ( ( strchr( format, '\n' ) != NULL || strchr( format, '\r' ) == NULL )
52        && pf_log != NULL )
53     {
54       va_start( arg, format );
55       vfprintf( pf_log, format, arg ); 
56       va_end( arg );
57       fflush( pf_log );
58     }
59 #  endif
60 }
61 #endif
62
63
64 #if defined(CSASHOGI)
65 void
66 out_csashogi( const char *format, ... )
67 {
68   va_list arg;
69
70   va_start( arg, format );
71   vprintf( format, arg );
72   va_end( arg );
73
74   fflush( stdout );
75 }
76 #endif
77
78
79 void
80 out_file( FILE *pf, const char *format, ... )
81 {
82   va_list arg;
83
84   if ( pf != NULL )
85     {
86       va_start( arg, format );
87       vfprintf( pf, format, arg ); 
88       va_end( arg );
89       fflush( pf );
90     }
91   
92 #if ! defined(NO_LOGGING)
93   if ( pf_log != NULL )
94     {
95       va_start( arg, format );
96       vfprintf( pf_log, format, arg ); 
97       va_end( arg );
98       fflush( pf_log );
99     }
100 #endif
101
102 }
103
104
105 void
106 out_warning( const char *format, ... )
107 {
108   va_list arg;
109   
110   fprintf( stderr, "\n%s", str_warning );
111   va_start( arg, format );
112   vfprintf( stderr, format, arg );
113   va_end( arg );
114   fprintf( stderr, "\n\n" );
115   fflush( stderr );
116   
117 #if ! defined(NO_LOGGING)
118   if ( pf_log != NULL )
119     {
120       fprintf( pf_log, "\n%s", str_warning );
121       va_start( arg, format );
122       vfprintf( pf_log, format, arg ); 
123       va_end( arg );
124       fprintf( pf_log, "\n\n" );
125       fflush( pf_log );
126     }
127 #endif
128
129 }
130
131
132 void
133 out_error( const char *format, ... )
134 {
135   va_list arg;
136   
137   fprintf( stderr, "\nERROR: " );
138   va_start( arg, format );
139   vfprintf( stderr, format, arg );
140   va_end( arg );
141   fprintf( stderr, "\n\n" );
142   fflush( stderr );
143   
144 #if ! defined(NO_LOGGING)
145   if ( pf_log != NULL )
146     {
147       fprintf( pf_log, "\nERROR: " );
148       va_start( arg, format );
149       vfprintf( pf_log, format, arg );
150       va_end( arg );
151       fprintf( pf_log, "\n\n" );
152       fflush( pf_log );
153     }
154 #endif
155   
156 }
157
158
159 FILE *
160 file_open( const char *str_file, const char *str_mode )
161 {
162   FILE *pf;
163
164   pf = fopen( str_file, str_mode );
165   if ( pf == NULL )
166     {
167       snprintf( str_message, SIZE_MESSAGE,
168                 "%s, %s", str_fopen_error, str_file );
169       str_error = str_message;
170       return NULL;
171     }
172   
173   return pf;
174 }
175
176
177 int
178 file_close( FILE *pf )
179 {
180   if ( pf == NULL ) { return 1; }
181   if ( ferror( pf ) )
182     {
183       fclose( pf );
184       str_error = str_io_error;
185       return -2;
186     }
187   if ( fclose( pf ) )
188     {
189       str_error = str_io_error;
190       return -2;
191     }
192
193   return 1;
194 }
195
196
197 void
198 show_prompt( void )
199 {
200   if ( game_status & flag_noprompt ) { return; }
201   
202 #if defined(DEKUNOBOU)
203   if ( dek_ngame )
204     {
205       Out( "Won=%3d Lost=%3d Total=%4d/", dek_win, dek_lost, dek_ngame-1 );
206     }
207 #endif
208
209   if ( game_status & flag_drawn ) { Out( "Drawn> " ); }
210   else if ( game_status & flag_mated )
211     {
212       if ( root_turn ) { Out( "Black Mated> " ); }
213       else             { Out( "White Mated> " ); }
214     }
215   else if ( game_status & flag_resigned )
216     {
217       if ( root_turn ) { Out( "White Resigned> " ); }
218       else             { Out( "Black Resigned> " ); }
219     }
220   else if ( game_status & flag_suspend )
221     {
222       if ( root_turn ) { Out( "White Suspend> " ); }
223       else             { Out( "Black Suspend> " ); }
224     }
225   else if ( root_turn ) { Out( "White %d> ", record_game.moves+1 ); }
226 #ifdef XBOARD
227 #  define SIGN "#"
228 #else
229 #  define SIGN
230 #endif
231   else                  { Out( SIGN "Black %d> ", record_game.moves+1 ); }
232 }
233
234
235 int
236 open_history( const char *str_name1, const char *str_name2 )
237 {
238 #if defined(NO_LOGGING)
239   char str_file[SIZE_FILENAME];
240   int iret;
241
242   iret = record_close( &record_game );
243   if ( iret < 0 ) { return -1; }
244
245   strncpy( str_file, "game.csa", SIZE_FILENAME-1 );
246   iret = record_open( &record_game, str_file, mode_read_write,
247                       str_name1, str_name2 );
248   if ( iret < 0 ) { return -1; }
249
250   return 1;
251 #else
252   FILE *pf;
253   int i, iret;
254   char str_file[SIZE_FILENAME];
255   
256   if ( record_game.pf != NULL && ! record_game.moves )
257     {
258       record_game.str_name1[0] = '\0';
259       record_game.str_name2[0] = '\0';
260
261       if ( str_name1 )
262         {
263           strncpy( record_game.str_name1, str_name1, SIZE_PLAYERNAME-1 );
264           record_game.str_name1[SIZE_PLAYERNAME-1] = '\0';
265         }
266       
267       if ( str_name2 )
268         {
269           strncpy( record_game.str_name2, str_name2, SIZE_PLAYERNAME-1 );
270           record_game.str_name2[SIZE_PLAYERNAME-1] = '\0';
271         }
272       return 1;
273     }
274
275   iret = file_close( pf_log );
276   if ( iret < 0 ) { return -1; }
277
278   iret = record_close( &record_game );
279   if ( iret < 0 ) { return -1; }
280   
281   for ( i = 0; i < 999; i++ )
282     {
283       snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
284                str_dir_logs, i );
285       pf = file_open( str_file, "r" );
286       if ( pf == NULL ) { break; }
287       iret = file_close( pf );
288       if ( iret < 0 ) { return -1; }
289     }
290   irecord_game = i;
291
292   snprintf( str_file, SIZE_FILENAME, "%s/n%03d.log",
293             str_dir_logs, i );
294   pf_log = file_open( str_file, "w" );
295   if ( pf_log == NULL ) { return -1; }
296
297   snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
298             str_dir_logs, i );
299   iret = record_open( &record_game, str_file, mode_read_write,
300                       str_name1, str_name2 );
301   if ( iret < 0 ) { return -1; }
302
303   return 1;
304 #endif
305 }
306
307
308 int
309 out_board( const tree_t * restrict ptree, FILE *pf, unsigned int move,
310            int is_strict )
311 {
312   int irank, ifile, i, iret, ito, ifrom;
313
314 #if ! defined(WIN32_PIPE)
315   int is_promote;
316 #endif
317
318   if ( ! is_strict && move )
319     {
320       ito        = I2To( move );
321       ifrom      = I2From( move );
322 #if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
323       is_promote = I2IsPromote( move );
324 #endif
325     }
326   else {
327     ito = ifrom = nsquare;
328 #if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
329     is_promote = 0;
330 #endif
331   }
332   
333   if ( ( game_status & flag_reverse ) && ! is_strict )
334     {
335       fprintf( pf, "          <reversed>        \n" );
336       fprintf( pf, "'  1  2  3  4  5  6  7  8  9\n" );
337
338       for ( irank = rank9; irank >= rank1; irank-- )
339         {
340           fprintf( pf, "P%d", irank + 1 );
341           
342           for ( ifile = file9; ifile >= file1; ifile-- )
343             {
344               i = irank * nfile + ifile;
345               iret = OutBoard0( pf, BOARD[i], i, ito, ifrom, is_promote );
346               if ( iret < 0 ) { return iret; }
347             }
348           fprintf( pf, "\n" );
349         }
350     }
351   else {
352     fprintf( pf, "'  9  8  7  6  5  4  3  2  1\n" );
353
354     for ( irank = rank1; irank <= rank9; irank++ )
355       {
356         fprintf( pf, "P%d", irank + 1 );
357         
358         for ( ifile = file1; ifile <= file9; ifile++ )
359           {
360             i = irank * nfile + ifile;
361             iret = OutBoard0( pf, BOARD[i], i, ito, ifrom, is_promote );
362             if ( iret < 0 ) { return iret; }
363           }
364         fprintf( pf, "\n" );
365       }
366   }
367     
368   out_hand( pf, HAND_B, "P+" );
369   out_hand( pf, HAND_W, "P-" );
370   fflush( pf );
371
372   return 1;
373 }
374
375
376 int
377 next_cmdline( int is_wait )
378 {
379   char *str_line_end;
380   size_t size;
381   int iret;
382
383   str_line_end = strchr( str_buffer_cmdline, '\n' );
384
385   if ( ! str_line_end )
386     {
387       if ( is_wait )
388         {
389           do {
390             iret = read_command( & str_line_end );
391             if ( iret < 0 ) { return iret; }
392           } while ( ! str_line_end && iret );
393           if ( ! iret )
394             {
395               game_status |= flag_quit;
396               return 1;
397             }
398         }
399       else {
400 #if defined(DEKUNOBOU)
401         if ( dek_ngame )
402           {
403             iret = dek_check();
404             goto tag;
405           }
406 #endif
407
408 #if defined(CSA_LAN)
409         if ( sckt_csa != SCKT_NULL )
410           {
411             iret = sckt_check( sckt_csa );
412             goto tag;
413           }
414 #endif
415
416 #if defined(MNJ_LAN)
417         if ( sckt_mnj != SCKT_NULL )
418           {
419             iret = sckt_check( sckt_mnj );
420             goto tag;
421           }
422 #endif
423         iret = check_input_buffer();
424         
425 #if defined(DEKUNOBOU) || defined(CSA_LAN) || defined(MNJ_LAN)
426     tag:
427 #endif
428         if ( iret <= 0 ) { return iret; }
429
430         iret = read_command( & str_line_end );
431         if ( iret < 0 ) { return iret; }
432         if ( ! iret )
433           {
434             game_status |= flag_quit;
435             return 1;
436           }
437         if ( ! str_line_end ) { return 0; }
438       }
439     }
440   
441   if ( str_line_end - str_buffer_cmdline + 1 >= SIZE_CMDLINE )
442     {
443       str_error = str_ovrflw_line;
444       memmove( str_buffer_cmdline, str_line_end + 1,
445                strlen( str_line_end + 1 ) + 1 );
446       return -2;
447     }
448   
449   size = str_line_end - str_buffer_cmdline;
450   memcpy( str_cmdline, str_buffer_cmdline, size );
451   *( str_cmdline + size ) = '\0';
452   
453 #if defined(DEKUNOBOU)
454   if ( dek_ngame )
455     {
456       iret = dek_parse( str_cmdline, SIZE_CMDLINE );
457       if ( iret < 0 )
458         {
459           memmove( str_buffer_cmdline, str_line_end + 1,
460                    strlen( str_line_end + 1 ) + 1 );
461           return iret;
462         }
463     }
464 #endif
465
466   if ( is_wait )
467     {
468       out_file( NULL, "%s\n", str_cmdline );
469       memmove( str_buffer_cmdline, str_line_end + 1,
470                strlen( str_line_end + 1 ) + 1 );
471     }
472
473   return 1;
474 }
475
476
477 static int
478 #if defined(NO_STDOUT) || defined(WIN32_PIPE)
479 out_board0( FILE *pf, int piece, int i, int ito, int ifrom )
480 #else
481 out_board0( FILE *pf, int piece, int i, int ito, int ifrom, int is_promote )
482 #endif
483 {
484   int ch;
485 #if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
486   int iret;
487 #endif
488
489   if ( piece )
490     {
491       ch = piece < 0 ? '-' : '+';
492 #if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
493       if ( i == ito && pf == stdout && ! ( game_status & flag_nostress ) )
494         {
495           iret = StdoutStress( is_promote, ifrom );
496           if ( iret < 0 )
497             {
498               fprintf( pf, "\n" );
499               return iret;
500             }
501         }
502 #endif
503       fprintf( pf, "%c%s", ch, astr_table_piece[ abs( piece ) ] );
504 #if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
505       if ( i == ito && pf == stdout && ! ( game_status & flag_nostress ) )
506         {
507           iret = StdoutNormal();
508           if ( iret < 0 )
509             {
510               fprintf( pf, "\n" );
511               return iret;
512             }
513         }
514 #endif
515     }
516   else {
517     if ( ifrom < nsquare
518          && ( ifrom == i
519               || ( adirec[ito][ifrom]
520                    && adirec[ito][ifrom] == adirec[ito][i]
521                    && ( ( ito < i && i <= ifrom )
522                         || ( ito > i && i >= ifrom ) ) ) ) )
523       {
524         fprintf( pf, "   " );
525       }
526     else { fprintf( pf, " * " ); }
527   }
528
529   return 1;
530 }
531
532
533 #if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
534
535 void
536 out_beep( void )
537 {
538   if ( game_status & flag_nobeep ) { return; }
539
540 #  if defined(_WIN32)
541   if ( ! MessageBeep( MB_OK ) )
542     {
543       out_warning( "Beep is not available." );
544     }
545 #  else
546   printf( "\007" );
547 #  endif
548 }
549
550
551 int
552 stdout_normal( void )
553 {
554 #  if defined(_WIN32)
555   HANDLE hStdout;
556   WORD wAttributes;
557   
558   hStdout = GetStdHandle( STD_OUTPUT_HANDLE );
559   if ( hStdout == INVALID_HANDLE_VALUE )
560     {
561       str_error = "GetStdHandle() faild";
562       return -1;
563     }
564
565   wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
566   if ( ! SetConsoleTextAttribute( hStdout, wAttributes ) )
567     {
568       str_error = "SetConsoleTextAttribute() faild";
569       return -1;
570     }
571
572 #  else
573   printf( "\033[0m" );
574 #  endif
575   return 1;
576 }
577
578
579 int
580 stdout_stress( int is_promote, int ifrom )
581 {
582 #  if defined(_WIN32)
583   HANDLE hStdout;
584   WORD wAttributes;
585
586   hStdout = GetStdHandle( STD_OUTPUT_HANDLE );
587   if ( hStdout == INVALID_HANDLE_VALUE )
588     {
589       str_error = "GetStdHandle() faild";
590       return -1;
591     }
592
593   if ( is_promote )
594     {
595       wAttributes = BACKGROUND_RED | BACKGROUND_INTENSITY;
596     }
597   else if ( ifrom >= nsquare )
598     {
599       wAttributes = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
600     }
601   else {
602     wAttributes = ( BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
603                     | BACKGROUND_INTENSITY );
604   }
605   if ( ! SetConsoleTextAttribute( hStdout, wAttributes ) )
606     {
607       str_error = "SetConsoleTextAttribute() faild";
608       return -1;
609     }
610 #  else
611   if      ( is_promote )       { printf( "\033[7;31m" ); }
612   else if ( ifrom >= nsquare ) { printf( "\033[7;34m" ); }
613   else                         { printf( "\033[7m" ); }
614 #  endif
615
616   return 1;
617 }
618
619 #endif /* no NO_STDOUT and no WIN32_PIPE */
620
621
622 static void
623 out_hand( FILE *pf, unsigned int hand, const char *str_prefix )
624 {
625   out_hand0( pf, (int)I2HandPawn(hand),   str_prefix, "00FU" );
626   out_hand0( pf, (int)I2HandLance(hand),  str_prefix, "00KY" );
627   out_hand0( pf, (int)I2HandKnight(hand), str_prefix, "00KE" );
628   out_hand0( pf, (int)I2HandSilver(hand), str_prefix, "00GI" );
629   out_hand0( pf, (int)I2HandGold(hand),   str_prefix, "00KI" );
630   out_hand0( pf, (int)I2HandBishop(hand), str_prefix, "00KA" );
631   out_hand0( pf, (int)I2HandRook(hand),   str_prefix, "00HI" );
632 }
633
634
635 static void
636 out_hand0( FILE *pf, int n, const char *str_prefix, const char *str )
637 {
638   int i;
639
640   if ( n > 0 )
641     {
642       fprintf( pf, str_prefix );
643       for ( i = 0; i < n; i++ ) { fprintf( pf, str ); }
644       fprintf( pf, "\n" );
645     }
646 }
647
648
649 static int
650 read_command( char ** pstr_line_end )
651 {
652   char *str_end;
653   int count_byte, count_cmdbuff;
654
655   count_cmdbuff = (int)strlen( str_buffer_cmdline );
656   str_end       = str_buffer_cmdline + count_cmdbuff;
657
658 #if defined(DEKUNOBOU)
659   if ( dek_ngame )
660     {
661       count_byte = dek_in( str_end, SIZE_CMDLINE-1-count_cmdbuff );
662       if ( count_byte < 0 ) { return count_byte; }
663       goto tag;
664     }
665 #endif
666
667 #if defined(CSA_LAN)
668   if ( sckt_csa != SCKT_NULL )
669     {
670       count_byte = sckt_in( sckt_csa, str_end, SIZE_CMDLINE-1-count_cmdbuff );
671       if ( count_byte < 0 ) { return count_byte; }
672       goto tag;
673     }
674 #endif
675
676 #if defined(MNJ_LAN)
677   if ( sckt_mnj != SCKT_NULL )
678     {
679       count_byte = sckt_in( sckt_mnj, str_end, SIZE_CMDLINE-1-count_cmdbuff );
680       if ( count_byte < 0 ) { return count_byte; }
681       goto tag;
682     }
683 #endif
684
685   do { count_byte = (int)read( 0, str_end, SIZE_CMDBUFFER-1-count_cmdbuff ); }
686   while ( count_byte < 0 && errno == EINTR );
687   
688   if ( count_byte < 0 )
689     {
690       str_error = "read() faild.";
691       return -1;
692     }
693   *( str_end + count_byte ) = '\0';
694
695 #if defined(DEKUNOBOU) || defined(CSA_LAN) || defined(MNJ_LAN)
696  tag:
697 #endif
698
699
700   *pstr_line_end = strchr( str_buffer_cmdline, '\n' );
701   if ( *pstr_line_end == NULL
702        && count_byte + count_cmdbuff + 1 >= SIZE_CMDLINE )
703     {
704       *str_buffer_cmdline = '\0';
705       str_error = str_ovrflw_line;
706       return -2;
707     }
708
709   return count_byte;
710 }
711
712 #if defined(_WIN32)
713
714 static int
715 check_input_buffer( void )
716 {
717 #  if defined(WIN32_PIPE)
718   BOOL bSuccess;
719   HANDLE hHandle;
720   DWORD dwBytesRead, dwTotalBytesAvail, dwBytesLeftThisMessage;
721   char buf[1];
722
723   hHandle = GetStdHandle( STD_INPUT_HANDLE );
724   if ( hHandle == INVALID_HANDLE_VALUE )
725     {
726       str_error = "GetStdHandle() faild.";
727       return -1;
728     }
729   bSuccess = PeekNamedPipe( hHandle, buf, 1, &dwBytesRead, &dwTotalBytesAvail,
730                             &dwBytesLeftThisMessage );
731   if ( ! bSuccess )
732     {
733       str_error = "PeekNamedPipe() faild.";
734       return -1;
735     }
736   if ( dwBytesRead ) { return 1; }
737   return 0;
738 #  else
739   return _kbhit();
740 #  endif
741 }
742
743 #else /* no _WIN32 */
744
745 static int
746 check_input_buffer( void )
747 {
748   fd_set readfds;
749   struct timeval tv;
750   int iret;
751
752 #if defined(__ICC)
753 #  pragma warning(disable:279)
754 #  pragma warning(disable:593)
755 #  pragma warning(disable:1469)
756 #endif
757
758   FD_ZERO(&readfds);
759   FD_SET(0, &readfds);
760   tv.tv_sec  = 0;
761   tv.tv_usec = 0;
762   iret       = select( 1, &readfds, NULL, NULL, &tv );
763   if ( iret == -1 )
764     {
765       str_error = "select() faild.";
766       return -1;
767     }
768   return iret;
769
770 #if defined(__ICC)
771 #  pragma warning(default:279)
772 #  pragma warning(default:593)
773 #  pragma warning(default:1469)
774 #endif
775 }
776
777 #endif /* no _WIN32 */