Upgrade to Bonanza 6.0
[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   else                  { Out( "Black %d> ", record_game.moves+1 ); }
237 }
238
239
240 int
241 open_history( const char *str_name1, const char *str_name2 )
242 {
243 #if defined(NO_LOGGING)
244   char str_file[SIZE_FILENAME];
245   int iret;
246
247   iret = record_close( &record_game );
248   if ( iret < 0 ) { return -1; }
249
250   iret = record_open( &record_game, "game.csa", mode_read_write,
251                       str_name1, str_name2 );
252   if ( iret < 0 ) { return -1; }
253
254   return 1;
255 #else
256   FILE *pf;
257   int i, iret;
258   char str_file[SIZE_FILENAME];
259   
260   if ( record_game.pf != NULL && ! record_game.moves )
261     {
262       record_game.str_name1[0] = '\0';
263       record_game.str_name2[0] = '\0';
264
265       if ( str_name1 )
266         {
267           strncpy( record_game.str_name1, str_name1, SIZE_PLAYERNAME-1 );
268           record_game.str_name1[SIZE_PLAYERNAME-1] = '\0';
269         }
270       
271       if ( str_name2 )
272         {
273           strncpy( record_game.str_name2, str_name2, SIZE_PLAYERNAME-1 );
274           record_game.str_name2[SIZE_PLAYERNAME-1] = '\0';
275         }
276       return 1;
277     }
278
279   if ( ( ( game_status & flag_nonewlog )
280 #  if defined(USI)
281          ||  usi_mode != usi_off
282 #  endif
283          ) && 0 <= record_num )
284     {
285       iret = record_close( &record_game );
286       if ( iret < 0 ) { return -1; }
287       
288       snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
289                 str_dir_logs, record_num );
290       iret = record_open( &record_game, str_file, mode_read_write,
291                           str_name1, str_name2 );
292       if ( iret < 0 ) { return -1; }
293     }
294   else
295     {
296       iret = file_close( pf_log );
297       if ( iret < 0 ) { return -1; }
298       
299       iret = record_close( &record_game );
300       if ( iret < 0 ) { return -1; }
301       
302       for ( i = 0; i < 999; i++ )
303         {
304           snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
305                     str_dir_logs, i );
306           pf = file_open( str_file, "r" );
307           if ( pf == NULL ) { break; }
308           iret = file_close( pf );
309           if ( iret < 0 ) { return -1; }
310         }
311       record_num = i;
312       
313       snprintf( str_file, SIZE_FILENAME, "%s/n%03d.log",
314                 str_dir_logs, i );
315       pf_log = file_open( str_file, "w" );
316       if ( pf_log == NULL ) { return -1; }
317       
318       snprintf( str_file, SIZE_FILENAME, "%s/game%03d.csa",
319                 str_dir_logs, i );
320       iret = record_open( &record_game, str_file, mode_read_write,
321                           str_name1, str_name2 );
322       if ( iret < 0 ) { return -1; }
323     }
324   
325   return 1;
326 #endif
327 }
328
329
330 int
331 out_board( const tree_t * restrict ptree, FILE *pf, unsigned int move,
332            int is_strict )
333 {
334   int irank, ifile, i, iret, ito, ifrom;
335
336 #if ! defined(WIN32_PIPE)
337   int is_promote;
338 #endif
339
340   if ( game_status & flag_nostdout ) { return 1; }
341
342   if ( ! is_strict && move )
343     {
344       ito        = I2To( move );
345       ifrom      = I2From( move );
346 #if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
347       is_promote = I2IsPromote( move );
348 #endif
349     }
350   else {
351     ito = ifrom = nsquare;
352 #if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
353     is_promote = 0;
354 #endif
355   }
356   
357   if ( ( game_status & flag_reverse ) && ! is_strict )
358     {
359       fprintf( pf, "          <reversed>        \n" );
360       fprintf( pf, "'  1  2  3  4  5  6  7  8  9\n" );
361
362       for ( irank = rank9; irank >= rank1; irank-- )
363         {
364           fprintf( pf, "P%d", irank + 1 );
365           
366           for ( ifile = file9; ifile >= file1; ifile-- )
367             {
368               i = irank * nfile + ifile;
369               iret = OutBoard0( pf, BOARD[i], i, ito, ifrom, is_promote );
370               if ( iret < 0 ) { return iret; }
371             }
372           fprintf( pf, "\n" );
373         }
374     }
375   else {
376     fprintf( pf, "'  9  8  7  6  5  4  3  2  1\n" );
377
378     for ( irank = rank1; irank <= rank9; irank++ )
379       {
380         fprintf( pf, "P%d", irank + 1 );
381         
382         for ( ifile = file1; ifile <= file9; ifile++ )
383           {
384             i = irank * nfile + ifile;
385             iret = OutBoard0( pf, BOARD[i], i, ito, ifrom, is_promote );
386             if ( iret < 0 ) { return iret; }
387           }
388         fprintf( pf, "\n" );
389       }
390   }
391     
392   out_hand( pf, HAND_B, "P+" );
393   out_hand( pf, HAND_W, "P-" );
394   fflush( pf );
395
396   return 1;
397 }
398
399
400 int
401 next_cmdline( int is_wait )
402 {
403   char *str_line_end;
404   size_t size;
405   int iret;
406
407   str_line_end = strchr( str_buffer_cmdline, '\n' );
408
409   if ( ! str_line_end )
410     {
411       if ( is_wait )
412         {
413           do {
414             iret = read_command( & str_line_end );
415             if ( iret < 0 ) { return iret; }
416           } while ( ! str_line_end && iret );
417           if ( ! iret )
418             {
419               game_status |= flag_quit;
420               return 1;
421             }
422         }
423       else {
424         iret = check_input_buffer();
425         if ( iret <= 0 ) { return iret; }
426
427         iret = read_command( & str_line_end );
428         if ( iret < 0 ) { return iret; }
429         if ( ! iret )
430           {
431             game_status |= flag_quit;
432             return 1;
433           }
434         if ( ! str_line_end ) { return 0; }
435       }
436     }
437   
438   if ( str_line_end - str_buffer_cmdline + 1 >= SIZE_CMDLINE )
439     {
440       str_error = str_ovrflw_line;
441       memmove( str_buffer_cmdline, str_line_end + 1,
442                strlen( str_line_end + 1 ) + 1 );
443       return -2;
444     }
445   
446   size = str_line_end - str_buffer_cmdline;
447   memcpy( str_cmdline, str_buffer_cmdline, size );
448   *( str_cmdline + size ) = '\0';
449   
450   if ( is_wait )
451     {
452       out_file( NULL, "%s\n", str_cmdline );
453       memmove( str_buffer_cmdline, str_line_end + 1,
454                strlen( str_line_end + 1 ) + 1 );
455     }
456
457   return 1;
458 }
459
460
461 static int
462 #if defined(NO_STDOUT) || defined(WIN32_PIPE)
463 out_board0( FILE *pf, int piece, int i, int ito, int ifrom )
464 #else
465 out_board0( FILE *pf, int piece, int i, int ito, int ifrom, int is_promote )
466 #endif
467 {
468   int ch;
469 #if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
470   int iret;
471 #endif
472
473   if ( piece )
474     {
475       ch = piece < 0 ? '-' : '+';
476 #if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
477       if ( i == ito && pf == stdout && ! ( game_status & flag_nostress ) )
478         {
479           iret = StdoutStress( is_promote, ifrom );
480           if ( iret < 0 )
481             {
482               fprintf( pf, "\n" );
483               return iret;
484             }
485         }
486 #endif
487       fprintf( pf, "%c%s", ch, astr_table_piece[ abs( piece ) ] );
488 #if ! ( defined(NO_STDOUT) || defined(WIN32_PIPE) )
489       if ( i == ito && pf == stdout && ! ( game_status & flag_nostress ) )
490         {
491           iret = StdoutNormal();
492           if ( iret < 0 )
493             {
494               fprintf( pf, "\n" );
495               return iret;
496             }
497         }
498 #endif
499     }
500   else {
501     if ( ifrom < nsquare
502          && ( ifrom == i
503               || ( adirec[ito][ifrom]
504                    && adirec[ito][ifrom] == adirec[ito][i]
505                    && ( ( ito < i && i <= ifrom )
506                         || ( ito > i && i >= ifrom ) ) ) ) )
507       {
508         fprintf( pf, "   " );
509       }
510     else { fprintf( pf, " * " ); }
511   }
512
513   return 1;
514 }
515
516
517 #if ! defined(NO_STDOUT) && ! defined(WIN32_PIPE)
518
519 void
520 out_beep( void )
521 {
522   if ( game_status & flag_nobeep ) { return; }
523
524 #  if defined(_WIN32)
525   if ( ! MessageBeep( MB_OK ) )
526     {
527       out_warning( "Beep is not available." );
528     }
529 #  else
530   printf( "\007" );
531 #  endif
532 }
533
534
535 int
536 stdout_normal( void )
537 {
538 #  if defined(_WIN32)
539   HANDLE hStdout;
540   WORD wAttributes;
541   
542   hStdout = GetStdHandle( STD_OUTPUT_HANDLE );
543   if ( hStdout == INVALID_HANDLE_VALUE )
544     {
545       str_error = "GetStdHandle() faild";
546       return -1;
547     }
548
549   wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
550   if ( ! SetConsoleTextAttribute( hStdout, wAttributes ) )
551     {
552       str_error = "SetConsoleTextAttribute() faild";
553       return -1;
554     }
555
556 #  else
557   printf( "\033[0m" );
558 #  endif
559   return 1;
560 }
561
562
563 int
564 stdout_stress( int is_promote, int ifrom )
565 {
566 #  if defined(_WIN32)
567   HANDLE hStdout;
568   WORD wAttributes;
569
570   hStdout = GetStdHandle( STD_OUTPUT_HANDLE );
571   if ( hStdout == INVALID_HANDLE_VALUE )
572     {
573       str_error = "GetStdHandle() faild";
574       return -1;
575     }
576
577   if ( is_promote )
578     {
579       wAttributes = BACKGROUND_RED | BACKGROUND_INTENSITY;
580     }
581   else if ( ifrom >= nsquare )
582     {
583       wAttributes = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
584     }
585   else {
586     wAttributes = ( BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
587                     | BACKGROUND_INTENSITY );
588   }
589   if ( ! SetConsoleTextAttribute( hStdout, wAttributes ) )
590     {
591       str_error = "SetConsoleTextAttribute() faild";
592       return -1;
593     }
594 #  else
595   if      ( is_promote )       { printf( "\033[7;31m" ); }
596   else if ( ifrom >= nsquare ) { printf( "\033[7;34m" ); }
597   else                         { printf( "\033[7m" ); }
598 #  endif
599
600   return 1;
601 }
602
603 #endif /* no NO_STDOUT and no WIN32_PIPE */
604
605
606 static void CONV
607 out_hand( FILE *pf, unsigned int hand, const char *str_prefix )
608 {
609   out_hand0( pf, (int)I2HandPawn(hand),   str_prefix, "00FU" );
610   out_hand0( pf, (int)I2HandLance(hand),  str_prefix, "00KY" );
611   out_hand0( pf, (int)I2HandKnight(hand), str_prefix, "00KE" );
612   out_hand0( pf, (int)I2HandSilver(hand), str_prefix, "00GI" );
613   out_hand0( pf, (int)I2HandGold(hand),   str_prefix, "00KI" );
614   out_hand0( pf, (int)I2HandBishop(hand), str_prefix, "00KA" );
615   out_hand0( pf, (int)I2HandRook(hand),   str_prefix, "00HI" );
616 }
617
618
619 static void CONV
620 out_hand0( FILE *pf, int n, const char *str_prefix, const char *str )
621 {
622   int i;
623
624   if ( n > 0 )
625     {
626       fprintf( pf, str_prefix );
627       for ( i = 0; i < n; i++ ) { fprintf( pf, str ); }
628       fprintf( pf, "\n" );
629     }
630 }
631
632
633 static int CONV
634 read_command( char ** pstr_line_end )
635 {
636   char *str_end;
637   int count_byte, count_cmdbuff;
638
639   count_cmdbuff = (int)strlen( str_buffer_cmdline );
640   str_end       = str_buffer_cmdline + count_cmdbuff;
641
642 #if defined(CSA_LAN)
643   if ( sckt_csa != SCKT_NULL )
644     {
645       count_byte = sckt_in( sckt_csa, str_end, SIZE_CMDLINE-1-count_cmdbuff );
646       if ( count_byte < 0 ) { return count_byte; }
647       goto tag;
648     }
649 #endif
650
651 #if defined(MNJ_LAN)
652   if ( sckt_mnj != SCKT_NULL )
653     {
654       count_byte = sckt_in( sckt_mnj, str_end, SIZE_CMDLINE-1-count_cmdbuff );
655       if ( count_byte < 0 ) { return count_byte; }
656       goto tag;
657     }
658 #endif
659
660 #if defined(DFPN)
661   if ( dfpn_sckt != SCKT_NULL )
662     {
663       count_byte = sckt_in( dfpn_sckt, str_end, SIZE_CMDLINE-1-count_cmdbuff );
664       if ( count_byte < 0 ) { return count_byte; }
665       goto tag;
666     }
667 #endif
668
669   do { count_byte = (int)read( 0, str_end, SIZE_CMDBUFFER-1-count_cmdbuff ); }
670   while ( count_byte < 0 && errno == EINTR );
671   
672   if ( count_byte < 0 )
673     {
674       str_error = "read() faild.";
675       return -1;
676     }
677   *( str_end + count_byte ) = '\0';
678
679 #if defined(CSA_LAN) || defined(MNJ_LAN) || defined(DFPN)
680  tag:
681 #endif
682
683 #if defined(USI)
684   if ( usi_mode != usi_off ) { Out( "IN: %s[END]\n", str_end );}
685 #endif
686
687   *pstr_line_end = strchr( str_buffer_cmdline, '\n' );
688   if ( *pstr_line_end == NULL
689        && count_byte + count_cmdbuff + 1 >= SIZE_CMDLINE )
690     {
691       *str_buffer_cmdline = '\0';
692       str_error = str_ovrflw_line;
693       return -2;
694     }
695
696   return count_byte;
697 }
698
699
700 static int CONV
701 check_input_buffer( void )
702 {
703 #if defined(CSA_LAN)
704   if ( sckt_csa != SCKT_NULL ) { return sckt_check( sckt_csa ); }
705 #endif
706   
707 #if defined(MNJ_LAN)
708   if ( sckt_mnj != SCKT_NULL ) { return sckt_check( sckt_mnj ); }
709 #endif
710
711 #if defined(DFPN)
712   if ( dfpn_sckt != SCKT_NULL ) { return sckt_check( dfpn_sckt ); }
713 #endif
714
715   {
716 #if defined(_WIN32) && defined(WIN32_PIPE)
717     BOOL bSuccess;
718     HANDLE hHandle;
719     DWORD dwBytesRead, dwTotalBytesAvail, dwBytesLeftThisMessage;
720     char buf[1];
721
722     hHandle = GetStdHandle( STD_INPUT_HANDLE );
723     if ( hHandle == INVALID_HANDLE_VALUE )
724       {
725         str_error = "GetStdHandle() faild.";
726         return -1;
727       }
728     bSuccess = PeekNamedPipe( hHandle, buf, 1, &dwBytesRead,
729                               &dwTotalBytesAvail, &dwBytesLeftThisMessage );
730     if ( ! bSuccess )
731       {
732         str_error = "PeekNamedPipe() faild.";
733         return -1;
734       }
735     if ( dwBytesRead ) { return 1; }
736     return 0;
737
738 #elif defined(_WIN32)
739
740     return _kbhit();
741
742 #else
743
744     fd_set readfds;
745     struct timeval tv;
746     int iret;
747
748 #  if defined(__ICC)
749 #    pragma warning(disable:279)
750 #    pragma warning(disable:593)
751 #    pragma warning(disable:1469)
752 #  endif
753     
754     FD_ZERO(&readfds);
755     FD_SET(0, &readfds);
756     tv.tv_sec  = 0;
757     tv.tv_usec = 0;
758     iret       = select( 1, &readfds, NULL, NULL, &tv );
759     if ( iret == -1 )
760       {
761         str_error = "select() faild.";
762         return -1;
763       }
764     return iret;
765     
766 #  if defined(__ICC)
767 #    pragma warning(default:279)
768 #    pragma warning(default:593)
769 #    pragma warning(default:1469)
770 #  endif
771 #endif /* no _WIN32 */
772   }
773 }
774
775
776 static void CONV
777 out_file( FILE *pf, const char *format, ... )
778 {
779   va_list arg;
780
781   if ( pf != NULL )
782     {
783       va_start( arg, format );
784       vfprintf( pf, format, arg ); 
785       va_end( arg );
786       fflush( pf );
787     }
788   
789 #if ! defined(NO_LOGGING)
790   if ( pf_log != NULL )
791     {
792       va_start( arg, format );
793       vfprintf( pf_log, format, arg ); 
794       va_end( arg );
795       fflush( pf_log );
796     }
797 #endif
798
799 }