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