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