1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2002-2006 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <sys/types.h>
25 #include <sys/socket.h>
46 char *random_agony(GAME g
)
52 if (n
== -1 || !config
.agony
|| !curses_initialized
||
53 (g
.mode
== MODE_HISTORY
&& !config
.historyagony
))
57 if ((fp
= fopen(config
.agonyfile
, "r")) == NULL
) {
59 cmessage(ERROR
, ANYKEY
, "%s: %s", config
.agonyfile
, strerror(errno
));
64 if (fscanf(fp
, " %[^\n] ", line
) == 1) {
65 agony
= Realloc(agony
, (n
+ 2) * sizeof(char *));
66 agony
[n
++] = strdup(trim(line
));
73 if (agony
[0] == NULL
|| !n
) {
79 return agony
[random() % n
];
82 void draw_board(GAME g
, int crow
, int ccol
)
85 int bcol
= 0, brow
= 0;
86 int maxy
= BOARD_HEIGHT
, maxx
= BOARD_WIDTH
;
87 int ncols
= 0, offset
= 1;
88 unsigned coords_y
= 8;
90 for (row
= 0; row
< maxy
; row
++) {
93 for (col
= 0; col
< maxx
; col
++) {
96 chtype piece
, movecount
= 0;
99 if (row
== 0 || row
== maxy
- 2) {
101 mvwaddch(boardw
, row
, col
,
103 ACS_LLCORNER
| CP_BOARD_GRAPHICS
:
104 ACS_ULCORNER
| CP_BOARD_GRAPHICS
));
105 else if (col
== maxx
- 2)
106 mvwaddch(boardw
, row
, col
,
108 ACS_LRCORNER
| CP_BOARD_GRAPHICS
:
109 ACS_URCORNER
| CP_BOARD_GRAPHICS
));
111 mvwaddch(boardw
, row
, col
,
113 ACS_BTEE
| CP_BOARD_GRAPHICS
:
114 ACS_TTEE
| CP_BOARD_GRAPHICS
));
117 mvwaddch(boardw
, row
, col
,
118 LINE_GRAPHIC(ACS_HLINE
| CP_BOARD_GRAPHICS
));
124 if ((row
% 2) && col
== maxx
- 1 && coords_y
) {
125 wattron(boardw
, CP_BOARD_COORDS
);
126 mvwprintw(boardw
, row
, col
, "%d", coords_y
--);
127 wattroff(boardw
, CP_BOARD_COORDS
);
131 if ((col
== 0 || col
== maxx
- 2) && row
!= maxy
- 1) {
133 mvwaddch(boardw
, row
, col
,
135 ACS_RTEE
| CP_BOARD_GRAPHICS
:
136 ACS_LTEE
| CP_BOARD_GRAPHICS
));
138 mvwaddch(boardw
, row
, col
,
139 LINE_GRAPHIC(ACS_VLINE
| CP_BOARD_GRAPHICS
));
144 if ((row
% 2) && !(col
% 4) && row
!= maxy
- 1) {
145 mvwaddch(boardw
, row
, col
,
146 LINE_GRAPHIC(ACS_VLINE
| CP_BOARD_GRAPHICS
));
150 if (!(col
% 4) && row
!= maxy
- 1) {
151 mvwaddch(boardw
, row
, col
,
152 LINE_GRAPHIC(ACS_PLUS
| CP_BOARD_GRAPHICS
));
163 if (((ncols
% 2) && !(offset
% 2)) || (!(ncols
% 2)
169 if (config
.validmoves
&& g
.b
[brow
][bcol
].valid
) {
170 attrs
= (attrwhich
== WHITE
) ? CP_BOARD_MOVES_WHITE
:
171 CP_BOARD_MOVES_BLACK
;
173 if (g
.b
[brow
][bcol
].movecount
) {
174 if (brow
+ 1 != crow
&& bcol
+ 1 != ccol
)
175 movecount
= (g
.b
[brow
][bcol
].movecount
+ '0');
179 attrs
= (attrwhich
== WHITE
) ? CP_BOARD_WHITE
:
182 if (row
== ROWTOMATRIX(crow
) && col
== COLTOMATRIX(ccol
)) {
183 attrs
= CP_BOARD_CURSOR
;
186 if (row
== ROWTOMATRIX(g
.sp
.row
) &&
187 col
== COLTOMATRIX(g
.sp
.col
)) {
188 attrs
= CP_BOARD_SELECTED
;
194 mvwaddch(boardw
, row
, col
, ' ' | attrs
);
197 waddch(boardw
, x_grid_chars
[bcol
] | CP_BOARD_COORDS
);
199 piece
= g
.b
[row
/ 2][bcol
].icon
;
204 if (g
.side
== WHITE
&& isupper(piece
))
206 else if (g
.side
== BLACK
&& islower(piece
))
209 waddch(boardw
, (piece
&& piece
!= int_to_piece(g
, OPEN_SQUARE
)) ? piece
| attrs
: ' ' | attrs
);
215 if (movecount
&& row
!= maxy
-1)
216 waddch(boardw
, movecount
| CP_BOARD_COUNT
);
218 waddch(boardw
, ' ' | attrs
);
226 mvwaddch(boardw
, row
, col
,
227 LINE_GRAPHIC(ACS_HLINE
| CP_BOARD_GRAPHICS
));
235 /* Convert the selected piece to SAN format and validate it. */
236 static char *board_to_san(GAME
*g
)
238 static char str
[MAX_PGN_MOVE_LEN
+ 1], *p
;
243 snprintf(str
, sizeof(str
), "%c%i%c%i", x_grid_chars
[(*g
).sp
.col
- 1],
244 (*g
).sp
.row
, x_grid_chars
[(*g
).sp
.destcol
- 1], (*g
).sp
.destrow
);
247 piece
= piece_to_int((*g
).b
[ROWTOBOARD((*g
).sp
.row
)][COLTOBOARD((*g
).sp
.col
)].icon
);
249 if (piece
== PAWN
&& (((*g
).sp
.destrow
== 8 && (*g
).turn
== WHITE
) ||
250 ((*g
).sp
.destrow
== 1 && (*g
).turn
== BLACK
))) {
251 promo
= cmessage(PROMOTION_TITLE
, PROMOTION_PROMPT
, PROMOTION_TEXT
);
253 if (piece_to_int(promo
) == -1)
256 p
= str
+ strlen(str
);
257 *p
++ = toupper(promo
);
261 memcpy(oldboard
, (*g
).b
, sizeof(BOARD
));
263 if ((p
= a2a4tosan(g
, str
)) == NULL
) {
264 cmessage(p
, ANYKEY
, "%s", E_A2A4_PARSE
);
265 memcpy((*g
).b
, oldboard
, sizeof(BOARD
));
269 if (parse_move_text(g
, p
)) {
270 invalid_move((*g
).n
, p
);
271 memcpy((*g
).b
, oldboard
, sizeof(BOARD
));
278 static int move_to_engine(GAME
*g
)
282 if ((p
= board_to_san(g
)) == NULL
)
285 (*g
).sp
.row
= (*g
).sp
.col
= (*g
).sp
.icon
= 0;
288 add_to_history(&(*g
).hp
, &(*g
).hindex
, &(*g
).htotal
, p
);
290 SET_FLAG((*g
).flags
, GF_MODIFIED
);
295 SEND_TO_ENGINE("%s\n", p
);
299 char *book_method(int method
)
305 book
= BOOK_BEST_STR
;
308 book
= BOOK_WORST_STR
;
311 book
= BOOK_PREFER_STR
;
314 book
= BOOK_RANDOM_STR
;
327 static void update_clock(int n
, int *h
, int *m
, int *s
)
330 *m
= (n
% 3600) / 60;
331 *s
= (n
% 3600) % 60;
336 void update_status_window(GAME g
)
339 char buf
[STATUS_WIDTH
- 7];
340 char tmp
[15], *engine
, *mode
;
341 int w
= STATUS_WIDTH
- 10;
348 if (TEST_FLAG(g
.flags
, GF_DELETE
)) {
354 if (TEST_FLAG(g
.flags
, GF_PERROR
)) {
364 if (TEST_FLAG(g
.flags
, GF_MODIFIED
)) {
379 mvwprintw(statusw
, 2, 1, "%*s %-*s", 7, STATUS_FILE_STR
, w
,
380 (loadfile
[0]) ? str_etc(loadfile
, w
, 1) : UNAVAILABLE
);
381 snprintf(buf
, sizeof(buf
), "%i %s %i %s", gindex
+ 1, N_OF_N_STR
, gtotal
,
383 mvwprintw(statusw
, 3, 1, "%*s %-*s", 7, STATUS_GAME_STR
, w
, buf
);
387 mode
= MODE_HISTORY_STR
;
390 mode
= MODE_EDIT_STR
;
393 mode
= MODE_PLAY_STR
;
400 mvwprintw(statusw
, 4, 1, "%*s %-*s", 7, STATUS_MODE_STR
, w
, mode
);
402 switch (status
.engine
) {
403 case ENGINE_THINKING
:
404 engine
= ENGINE_THINKING_STR
;
407 engine
= ENGINE_READY_STR
;
409 case ENGINE_INITIALIZING
:
410 engine
= ENGINE_INITIALIZING_STR
;
413 engine
= ENGINE_OFFLINE_STR
;
420 mvwprintw(statusw
, 5, 1, "%*s %-*s", 7, STATUS_ENGINE_STR
, w
, " ");
421 wattron(statusw
, CP_STATUS_ENGINE
);
422 mvwaddstr(statusw
, 5, 9, engine
);
423 wattroff(statusw
, CP_STATUS_ENGINE
);
425 mvwprintw(statusw
, 6, 1, "%*s %-*i", 7, STATUS_DEPTH_STR
, w
,
426 config
.engine_depth
);
428 mvwprintw(statusw
, 7, 1, "%*s %-*s", 7, STATUS_BOOK_STR
, w
,
429 book_method(config
.book_method
));
431 mvwprintw(statusw
, 8, 1, "%*s %-*s", 7, STATUS_TURN_STR
, w
,
432 (g
.turn
== WHITE
) ? WHITE_STR
: BLACK_STR
);
434 strncpy(tmp
, WHITE_STR
, sizeof(tmp
));
435 tmp
[0] = toupper(tmp
[0]);
436 update_clock(g
.moveclock
, &h
, &m
, &s
);
437 snprintf(buf
, sizeof(buf
), "c/%-2i %.2i:%.2i:%.2i", g
.wcaptures
, h
, m
, s
);
438 mvwprintw(statusw
, 9, 1, "%*s: %-*s", 6, tmp
, w
, buf
);
440 strncpy(tmp
, BLACK_STR
, sizeof(tmp
));
441 tmp
[0] = toupper(tmp
[0]);
442 update_clock(g
.moveclock
, &h
, &m
, &s
);
443 snprintf(buf
, sizeof(buf
), "c/%-2i %.2i:%.2i:%.2i", g
.bcaptures
, h
, m
, s
);
444 mvwprintw(statusw
, 10, 1, "%*s: %-*s", 6, tmp
, w
, buf
);
446 for (i
= 1; i
< STATUS_WIDTH
- 4; i
++)
447 mvwprintw(statusw
, STATUS_HEIGHT
- 2, i
, " ");
450 status
.notify
= strdup(GAME_HELP_PROMPT
);
452 wattron(statusw
, CP_STATUS_NOTIFY
);
453 mvwprintw(statusw
, STATUS_HEIGHT
- 2,
454 CENTERX(STATUS_WIDTH
, status
.notify
), "%s", status
.notify
);
455 wattroff(statusw
, CP_STATUS_NOTIFY
);
458 void update_history_window(GAME g
)
460 char buf
[HISTORY_WIDTH
];
464 memset(&h
, 0, sizeof(HISTORY
));
465 n
= (g
.hindex
+ 1) / 2;
468 total
= (g
.htotal
+ 1) / 2;
470 total
= g
.htotal
/ 2;
473 snprintf(buf
, sizeof(buf
), "%u %s %u%s",n
, N_OF_N_STR
, total
,
474 (movestep
== 1) ? HISTORY_MOVE_STEP
: "");
476 strncpy(buf
, UNAVAILABLE
, sizeof(buf
));
478 mvwprintw(historyw
, 2, 1, "%*s %-*s", 10, HISTORY_MOVE_STR
,
479 HISTORY_WIDTH
- 13, buf
);
481 if (history_by_index(g
, g
.hindex
, &h
))
482 memset(&h
, 0, sizeof(HISTORY
));
484 snprintf(buf
, sizeof(buf
), "%s %s", (h
.move
[0]) ? h
.move
: UNAVAILABLE
,
485 ((h
.comment
&& h
.comment
[0]) || h
.nag
[0]) ? HISTORY_ANNO_NEXT
: "");
486 mvwprintw(historyw
, 3, 1, "%s %-*s", HISTORY_MOVE_NEXT_STR
,
487 HISTORY_WIDTH
- 13, buf
);
489 if (history_by_index(g
, game
[gindex
].hindex
- 1, &h
))
490 memset(&h
, 0, sizeof(HISTORY
));
492 snprintf(buf
, sizeof(buf
), "%s %s", (h
.move
[0]) ? h
.move
: UNAVAILABLE
,
493 ((h
.comment
&& h
.comment
[0]) || h
.nag
[0]) ? HISTORY_ANNO_PREV
: "");
494 mvwprintw(historyw
, 4, 1, "%s %-*s", HISTORY_MOVE_PREV_STR
,
495 HISTORY_WIDTH
- 13, buf
);
498 void update_tag_window(TAG
*t
)
501 int w
= TAG_WIDTH
- 10;
503 for (i
= 0; i
< 7; i
++) {
504 char *value
= t
[i
].value
;
507 if ((*value
== '?' || *value
== '-') && value
[1] == '\0')
509 else if (strcmp(t
[i
].name
, "Result") == 0) {
510 for (n
= 0; n
< NARRAY(fancy_results
); n
++) {
511 if (strcmp(value
, fancy_results
[n
].pgn
) == 0) {
512 value
= fancy_results
[n
].fancy
;
518 value
= str_etc(value
, w
, 0);
519 mvwprintw(tagw
, (i
+ 2), 1, "%*s: %-*s", 6, t
[i
].name
, w
, value
);
523 void draw_prompt(WINDOW
*win
, int y
, int width
, const char *str
, chtype attr
)
529 for (i
= 1; i
< width
- 1; i
++)
530 mvwaddch(win
, y
, i
, ' ');
532 mvwprintw(win
, y
, CENTERX(width
, str
), "%s", str
);
536 void draw_window_title(WINDOW
*win
, const char *title
, int width
, chtype attr
,
544 for (i
= 1; i
< width
- 1; i
++)
545 mvwaddch(win
, 1, i
, ' ');
547 mvwprintw(win
, 1, CENTERX(width
, title
), "%s", title
);
552 box(win
, ACS_VLINE
, ACS_HLINE
);
553 wattroff(win
, battr
);
556 void update_all(GAME g
)
558 update_status_window(g
);
559 update_history_window(g
);
562 static void game_next_prev(GAME g
, int n
, int count
)
568 if (gindex
+ count
> gtotal
- 1) {
578 if (gindex
- count
< 0) {
590 update_tag_window(g
.tag
);
593 void free_game_data(GAME g
)
595 free_history_data(g
.history
, 0);
596 free_tag_data(g
.tag
, g
.tindex
);
597 memset(&g
, 0, sizeof(GAME
));
600 void free_all_games()
604 for (i
= 0; i
< gtotal
; i
++)
605 free_game_data(game
[i
]);
612 static void delete_game(int which
)
618 for (i
= 0; i
< gtotal
; i
++) {
619 if (i
== which
|| TEST_FLAG(game
[i
].flags
, GF_DELETE
)) {
620 free_game_data(game
[i
]);
624 g
= Realloc(g
, (gi
+ 1) * sizeof(GAME
));
625 memcpy(&g
[gi
], &game
[i
], sizeof(GAME
));
626 g
[gi
].tag
= game
[i
].tag
;
627 g
[gi
].history
= game
[i
].history
;
628 g
[gi
].hp
= game
[i
].hp
;
636 if (which
+ 1 >= gtotal
)
644 game
[gindex
].hp
= game
[gindex
].history
;
647 /* FIXME dont show out of reach counts. Diagonals. */
649 static void number_valid_moves(BOARD b, int srow, int scol)
654 for (row = srow + 1, col = scol, count = 1; VALIDFILE(row); row++) {
655 if (!b[ROWTOBOARD(row)][COLTOBOARD(col)].valid)
658 b[ROWTOBOARD(row)][COLTOBOARD(col)].movecount = count++;
661 for (row = srow - 1, col = scol, count = 1; VALIDFILE(row); row--) {
662 if (!b[ROWTOBOARD(row)][COLTOBOARD(col)].valid)
665 b[ROWTOBOARD(row)][COLTOBOARD(col)].movecount = count++;
668 for (col = scol + 1, row = srow, count = 1; VALIDFILE(col); col++) {
669 if (!b[ROWTOBOARD(row)][COLTOBOARD(col)].valid)
672 b[ROWTOBOARD(row)][COLTOBOARD(col)].movecount = count++;
675 for (col = scol - 1, row = srow, count = 1; VALIDFILE(col); col--) {
676 if (!b[ROWTOBOARD(row)][COLTOBOARD(col)].valid)
679 b[ROWTOBOARD(row)][COLTOBOARD(col)].movecount = count++;
687 static void get_valid_cursor(BOARD b, int which, int count, int *crow,
688 int *ccol, int minr, int maxr, int minc, int maxc)
693 if (which == UP || which == RIGHT)
709 if (!VALIDFILE(*crow))
713 for (row = *crow + incr, col = *ccol; VALIDFILE(row); row += incr) {
714 if (!b[ROWTOBOARD(row)][COLTOBOARD(col)].valid)
732 if (!VALIDFILE(*ccol))
736 for (col = *ccol + incr, row = *crow; VALIDFILE(col); col += incr) {
737 if (!b[ROWTOBOARD(row)][COLTOBOARD(col)].valid)
749 if (*ccol < sp.col || (which == DOWN || which == LEFT))
754 if (*ccol < sp.col && (which == DOWN || which == LEFT))
757 for (row = *crow + incr; VALIDFILE(row); row += incr) {
758 for (col = *ccol + cincr; VALIDFILE(col); col += cincr) {
759 if (!b[ROWTOBOARD(row)][COLTOBOARD(col)].valid)
769 number_valid_moves(board, *crow, *ccol);
774 static int find_move_exp(GAME g
, const char *str
, int init
, int which
,
780 static int firstrun
= 1;
789 if ((ret
= regcomp(&r
, str
, REG_EXTENDED
|REG_NOSUB
)) != 0) {
790 regerror(ret
, &r
, errbuf
, sizeof(errbuf
));
791 cmessage(E_REGCOMP_TITLE
, ANYKEY
, "%s", errbuf
);
798 incr
= (which
== 0) ? -(1) : 1;
800 for (i
= g
.hindex
+ incr
- 1, found
= 0; ; i
+= incr
) {
801 if (i
== g
.hindex
- 1)
810 ret
= regexec(&r
, g
.hp
[i
].move
, 0, 0, 0);
813 if (count
== ++found
) {
818 if (ret
!= REG_NOMATCH
) {
819 regerror(ret
, &r
, errbuf
, sizeof(errbuf
));
820 cmessage(E_REGEXEC_TITLE
, ANYKEY
, "%s", errbuf
);
829 static int toggle_delete_flag(int n
)
833 TOGGLE_FLAG(game
[n
].flags
, GF_DELETE
);
835 for (i
= x
= 0; i
< gtotal
; i
++) {
836 if (TEST_FLAG(game
[i
].flags
, GF_DELETE
))
841 cmessage(NULL
, ANYKEY
, "%s", E_DELETE_GAME
);
842 CLEAR_FLAG(game
[n
].flags
, GF_DELETE
);
849 static void edit_save_tags(GAME
*g
)
854 if ((t
= edit_tags(*g
, 1)) == NULL
)
859 for (i
= 0; t
[i
].name
; i
++)
860 add_tag(&(*g
).tag
, &(*g
).tindex
, t
[i
].name
, t
[i
].value
);
863 SET_FLAG((*g
).flags
, GF_MODIFIED
);
866 static int find_game_exp(char *str
, int which
, int count
)
868 char *nstr
= NULL
, *exp
= NULL
;
875 int incr
= (which
== 0) ? -(1) : 1;
877 strncpy(buf
, str
, sizeof(buf
));
880 if (strstr(tmp
, ":") != NULL
) {
881 nstr
= strsep(&tmp
, ":");
883 if ((ret
= regcomp(&nexp
, nstr
,
884 REG_ICASE
|REG_EXTENDED
|REG_NOSUB
)) != 0) {
885 regerror(ret
, &nexp
, errbuf
, sizeof(errbuf
));
886 cmessage(E_REGCOMP_TITLE
, ANYKEY
, "%s", errbuf
);
897 if ((ret
= regcomp(&vexp
, exp
, REG_EXTENDED
|REG_NOSUB
)) != 0) {
898 regerror(ret
, &vexp
, errbuf
, sizeof(errbuf
));
899 cmessage(E_REGCOMP_TITLE
, ANYKEY
, "%s", errbuf
);
906 for (g
= gindex
+ incr
, found
= 0; ; g
+= incr
) {
917 for (t
= 0; t
< game
[g
].tindex
; t
++) {
919 if (regexec(&nexp
, game
[g
].tag
[t
].name
, 0, 0, 0) == 0) {
920 if (regexec(&vexp
, game
[g
].tag
[t
].value
, 0, 0, 0) == 0) {
921 if (count
== ++found
) {
929 if (regexec(&vexp
, game
[g
].tag
[t
].value
, 0, 0, 0) == 0) {
930 if (count
== ++found
) {
951 void edit_board(GAME
*g
)
955 p
= (*g
).b
[ROWTOBOARD((*g
).sp
.row
)][COLTOBOARD((*g
).sp
.col
)].icon
;
956 (*g
).b
[ROWTOBOARD((*g
).sp
.destrow
)][COLTOBOARD((*g
).sp
.destcol
)].icon
= p
;
957 (*g
).b
[ROWTOBOARD((*g
).sp
.row
)][COLTOBOARD((*g
).sp
.col
)].icon
=
958 int_to_piece(*g
, OPEN_SQUARE
);
961 // Updates the notification line in the status window then refreshes the
963 void update_status_notify(GAME g
, char *fmt
, ...)
966 #ifdef HAVE_VASPRINTF
975 status
.notify
= NULL
;
977 if (curses_initialized
)
978 update_status_window(g
);
985 #ifdef HAVE_VASPRINTF
986 vasprintf(&line
, fmt
, ap
);
988 vsnprintf(line
, sizeof(line
), fmt
, ap
);
995 status
.notify
= strdup(line
);
997 #ifdef HAVE_VASPRINTF
1000 if (curses_initialized
)
1001 update_status_window(g
);
1004 static void switch_side(GAME
*g
)
1006 if ((*g
).side
== WHITE
)
1012 static struct annotation_edit_s
*init_annotation_edit(int g
, int n
, HISTORY h
)
1014 struct annotation_edit_s
*a
;
1016 a
= Malloc(sizeof(struct annotation_edit_s
));
1019 memcpy(&a
->h
, &h
, sizeof(HISTORY
));
1020 a
->h
.comment
= h
.comment
;
1026 int error_recover
= 0;
1029 int crow
= 2, ccol
= 5;
1030 char moveexp
[255] = {0};
1031 char gameexp
[255] = {0};
1032 int delete_count
= 0;
1033 int markstart
= -1, markend
= -1;
1036 gindex
= gtotal
- 1;
1037 markstart
= -1, markend
= -1;
1040 init_history(&game
[gindex
]);
1042 update_status_notify(game
[gindex
], "%s", GAME_HELP_PROMPT
);
1044 paused
= 1; //FIXME clock
1046 update_all(game
[gindex
]);
1047 update_tag_window(game
[gindex
].tag
);
1052 int i
, x
, n
= 0, len
= 0;
1053 char fdbuf
[8192] = {0};
1057 char tfile
[FILENAME_MAX
];
1058 int minr
, maxr
, minc
, maxc
;
1059 struct annotation_edit_s
*anno
= NULL
;
1063 if (engine_initialized
) {
1068 FD_SET(enginefd
[0], &fds
);
1070 for (i
= 0; i
< gtotal
; i
++) {
1071 if (game
[i
].sockfd
> 0) {
1072 if (game
[i
].sockfd
> n
)
1075 FD_SET(game
[i
].sockfd
, &fds
);
1079 n
= (n
> enginefd
[0]) ? n
: enginefd
[0];
1081 if ((n
= select(n
+ 1, &fds
, NULL
, NULL
, &tv
)) > 0) {
1082 if (FD_ISSET(enginefd
[0], &fds
)) {
1083 len
= read(enginefd
[0], fdbuf
, sizeof(fdbuf
));
1086 if (errno
!= EAGAIN
) {
1087 cmessage(ERROR
, ANYKEY
, "Attempt #%i. read(): %s",
1088 ++error_recover
, strerror(errno
));
1094 // FIXME engine may be associated with another
1096 parse_engine_output(&game
[gindex
], fdbuf
);
1097 update_all(game
[gindex
]);
1102 for (i
= 0; i
< gtotal
; i
++) {
1103 if (game
[i
].sockfd
<= 0)
1106 if (FD_ISSET(game
[i
].sockfd
, &fds
)) {
1107 len
= recv(game
[i
].sockfd
, fdbuf
, sizeof(fdbuf
), 0);
1110 if (errno
!= EAGAIN
) {
1111 cmessage(ERROR
, ANYKEY
,
1112 "Attempt #%i. recv(): %s",
1113 ++error_recover
, strerror(errno
));
1119 parse_ics_output(fdbuf
);
1121 update_all(game
[gindex
]);
1128 cmessage(ERROR
, ANYKEY
, "select(): %s", strerror(errno
));
1137 draw_board(game
[gindex
], crow
, ccol
);
1138 wmove(boardw
, ROWTOMATRIX(crow
), COLTOMATRIX(ccol
));
1149 if ((c
= wgetch(boardw
)) == ERR
)
1153 if (!count
&& status
.notify
)
1154 update_status_notify(game
[gindex
], NULL
);
1167 if (game
[gindex
].htotal
)
1172 add_tag(&game
[gindex
].tag
, &game
[gindex
].tindex
,
1173 "FEN", board_to_fen(game
[gindex
]));
1174 add_tag(&game
[gindex
].tag
, &game
[gindex
].tindex
,
1176 game
[gindex
].mode
= MODE_PLAY
;
1177 game
[gindex
].fentag
= find_tag(game
[gindex
].tag
,
1178 game
[gindex
].tindex
, "FEN");
1181 game
[gindex
].mode
= MODE_EDIT
;
1185 update_all(game
[gindex
]);
1193 if (!*gameexp
|| c
== '?') {
1194 if ((tmp
= get_input(GAME_FIND_EXPRESSION_TITLE
, gameexp
,
1195 1, 1, GAME_FIND_EXPRESSION_PROMPT
, NULL
,
1196 NULL
, 0, -1)) == NULL
)
1199 strncpy(gameexp
, tmp
, sizeof(gameexp
));
1202 if ((n
= find_game_exp(gameexp
, (c
== '{') ? 0 : 1,
1203 (count
) ? count
: 1)) == -1)
1207 init_history(&game
[gindex
]);
1208 update_all(game
[gindex
]);
1209 update_tag_window(game
[gindex
].tag
);
1261 if (status
.engine
!= ENGINE_READY
)
1264 n
= (count
) ? count
: 1;
1267 if (config
.engine_depth
- n
< 0)
1270 n
-= config
.engine_depth
;
1273 n
+= config
.engine_depth
;
1275 SEND_TO_ENGINE("depth %i\n", abs(n
));
1280 if (game
[gindex
].htotal
< 2)
1285 if (!*moveexp
|| c
== '/') {
1286 if ((tmp
= get_input(FIND_REGEXP
, moveexp
, 1, 1, NULL
,
1287 NULL
, NULL
, 0, -1)) == NULL
)
1290 strncpy(moveexp
, tmp
, sizeof(moveexp
));
1294 if ((n
= find_move_exp(game
[gindex
], moveexp
, n
,
1295 (c
== '[') ? 0 : 1, (count
) ? count
: 1)) == -1)
1298 game
[gindex
].hindex
= n
;
1299 parse_history_move(game
[gindex
], game
[gindex
].hindex
);
1300 update_all(game
[gindex
]);
1303 view_annotation(game
[gindex
].hp
[game
[gindex
].hindex
]);
1306 if (game
[gindex
].hindex
- 1 >= 0)
1307 view_annotation(game
[gindex
].hp
[game
[gindex
].hindex
- 1]);
1310 game_next_prev(game
[gindex
], 1, (count
) ? count
: 1);
1318 game
[gindex
].mode
= MODE_HISTORY
;
1322 game_next_prev(game
[gindex
], 0, (count
) ? count
: 1);
1330 game
[gindex
].mode
= MODE_HISTORY
;
1334 if (game
[gindex
].mode
!= MODE_HISTORY
||
1335 game
[gindex
].htotal
< 2)
1339 if ((tmp = get_input(GAME_HISTORY_JUMP_TITLE, NULL, 1, 1,
1340 NULL, NULL, NULL, 0, FIELD_TYPE_INTEGER, 1, 0,
1341 game[gindex].htotal)) == NULL)
1346 if ((tmp
= get_input(GAME_HISTORY_JUMP_TITLE
, NULL
, 1, 1,
1347 NULL
, NULL
, NULL
, 0, -1)) == NULL
)
1350 if (!isinteger(tmp
))
1358 if (i
> (game
[gindex
].htotal
/ 2) || i
< 0)
1361 game
[gindex
].hindex
= i
* 2;
1362 init_history(&game
[gindex
]);
1363 update_all(game
[gindex
]);
1370 if ((tmp = get_input(GAME_JUMP_TITLE, NULL, 1, 1, NULL, NULL,
1371 NULL, 0, FIELD_TYPE_INTEGER, 1, 1, gtotal))
1377 if ((tmp
= get_input(GAME_JUMP_TITLE
, NULL
, 1, 1, NULL
,
1378 NULL
, NULL
, 0, -1)) == NULL
)
1381 if (!isinteger(tmp
))
1389 if (--i
> gtotal
- 1 || i
< 0)
1393 init_history(&game
[gindex
]);
1394 update_all(game
[gindex
]);
1395 update_tag_window(game
[gindex
].tag
);
1401 if (game
[gindex
].sp
.icon
)
1402 game
[gindex
].b
[ROWTOBOARD(game
[gindex
].sp
.row
)][COLTOBOARD(game
[gindex
].sp
.col
)].icon
= int_to_piece(game
[gindex
], OPEN_SQUARE
);
1404 game
[gindex
].b
[ROWTOBOARD(crow
)][COLTOBOARD(ccol
)].icon
= int_to_piece(game
[gindex
], OPEN_SQUARE
);
1406 game
[gindex
].sp
.icon
= game
[gindex
].sp
.row
= game
[gindex
].sp
.col
= 0;
1413 if (count
&& !delete_count
) {
1416 update_status_notify(game
[gindex
], "%s (delete)",
1421 if (markstart
>= 0 && markend
>= 0) {
1422 if (markstart
> markend
) {
1424 markstart
= markend
;
1428 for (i
= markstart
; i
<= markend
; i
++) {
1429 if (toggle_delete_flag(i
))
1434 if (toggle_delete_flag(gindex
))
1438 markstart
= markend
= -1;
1439 update_status_window(game
[gindex
]);
1443 cmessage(NULL
, ANYKEY
, "%s", E_DELETE_GAME
);
1449 for (i
= n
= 0; i
< gtotal
; i
++) {
1450 if (TEST_FLAG(game
[i
].flags
, GF_DELETE
))
1455 tmp
= GAME_DELETE_GAME_TEXT
;
1458 cmessage(NULL
, ANYKEY
, "%s", E_DELETE_GAME
);
1462 tmp
= GAME_DELETE_ALL_TEXT
;
1465 if (config
.deleteprompt
) {
1466 if ((c
= cmessage(NULL
, YESNO
, "%s", tmp
)) != 'y')
1470 delete_game((!n
) ? gindex
: -1);
1471 init_history(&game
[gindex
]);
1472 update_all(game
[gindex
]);
1473 update_tag_window(game
[gindex
].tag
);
1476 annotate
= game
[gindex
].hindex
;
1478 if (annotate
&& game
[gindex
].hp
[annotate
- 1].move
[0])
1483 snprintf(buf
, sizeof(buf
), "%s \"%s\"", ANNOTATION_EDIT_TITLE
,
1484 game
[gindex
].hp
[annotate
].move
);
1486 anno
= init_annotation_edit(gindex
, annotate
,
1487 game
[gindex
].hp
[annotate
]);
1488 tmp
= get_input(buf
, game
[gindex
].hp
[annotate
].comment
,
1489 0, 0, NAG_PROMPT
, history_edit_nag
, (void *)anno
,
1492 if (!tmp
&& (!game
[gindex
].hp
[annotate
].comment
||
1493 !*game
[gindex
].hp
[annotate
].comment
))
1495 else if (tmp
&& game
[gindex
].hp
[annotate
].comment
) {
1496 if (strcmp(tmp
, game
[gindex
].hp
[annotate
].comment
) == 0)
1500 len
= (tmp
) ? strlen(tmp
) + 1 : 1;
1502 game
[gindex
].hp
[annotate
].comment
=
1503 Realloc(game
[gindex
].hp
[annotate
].comment
, len
);
1505 strncpy(game
[gindex
].hp
[annotate
].comment
,
1506 (tmp
) ? tmp
: "", len
);
1508 SET_FLAG(game
[gindex
].flags
, GF_MODIFIED
);
1509 update_all(game
[gindex
]);
1512 edit_save_tags(&game
[gindex
]);
1513 update_all(game
[gindex
]);
1514 update_tag_window(game
[gindex
].tag
);
1520 c
= message(GAME_EDIT_TITLE
, GAME_EDIT_PROMPT
, "%s",
1523 if (piece_to_int(c
) == -1 && tolower(c
) != 'x')
1526 if (tolower(c
) == 'x')
1529 if (c
== 'x' && (crow
!= 6 && crow
!= 3))
1533 for (i
= 0; i
< 8; i
++) {
1534 if (game
[gindex
].b
[ROWTOBOARD(3)][COLTOBOARD(i
)].icon
== 'x')
1535 game
[gindex
].b
[ROWTOBOARD(3)][COLTOBOARD(i
)].icon
= OPEN_SQUARE
;
1536 if (game
[gindex
].b
[ROWTOBOARD(6)][COLTOBOARD(i
)].icon
== 'x')
1537 game
[gindex
].b
[ROWTOBOARD(6)][COLTOBOARD(i
)].icon
= OPEN_SQUARE
;
1541 game
[gindex
].b
[ROWTOBOARD(crow
)][COLTOBOARD(ccol
)].icon
= c
;
1544 edit_tags(game
[gindex
], 0);
1547 if (game
[gindex
].mode
== MODE_HISTORY
||
1548 status
.engine
== ENGINE_THINKING
)
1551 status
.engine
= ENGINE_THINKING
;
1552 update_status_window(game
[gindex
]);
1553 SEND_TO_ENGINE("go\n");
1556 if (config
.book_method
== -1 || status
.engine
==
1557 ENGINE_THINKING
|| config
.engine
!= GNUCHESS
)
1560 if (config
.book_method
+ 1 >= BOOK_MAX
)
1563 n
= config
.book_method
+ 1;
1565 SEND_TO_ENGINE("book %s\n", book_methods
[n
]);
1568 if (game
[gindex
].mode
== MODE_HISTORY
) {
1569 if (game
[gindex
].openingside
== BLACK
) {
1570 cmessage(NULL
, ANYKEY
, "%s", E_RESUME_BLACK
);
1574 if (game
[gindex
].hindex
!= game
[gindex
].htotal
) {
1576 if ((c
= message(NULL
, YESNO
, "%s",
1577 GAME_RESUME_HISTORY_TEXT
)) != 'y')
1582 if (TEST_FLAG(game
[gindex
].flags
, GF_GAMEOVER
))
1587 wtimeout(boardw
, 70);
1589 if (!noengine
&& !engine_initialized
) {
1590 if (start_chess_engine() < 0)
1598 oldhistorytotal
= game
[gindex
].htotal
;
1599 game
[gindex
].htotal
= game
[gindex
].hindex
;
1600 game
[gindex
].mode
= MODE_PLAY
;
1601 status
.engine
= ENGINE_READY
;
1604 if (config
.engine
!= GNUCHESS
)
1605 SEND_TO_ENGINE("read %s\n", config
.fifo
);
1607 SEND_TO_ENGINE("\npgnload %s\n", config
.fifo
);
1609 update_all(game
[gindex
]);
1613 if (!game
[gindex
].htotal
|| status
.engine
== ENGINE_THINKING
)
1616 wtimeout(boardw
, -1);
1617 init_history(&game
[gindex
]);
1620 /* FIXME dies reading FIFO sometimes. */
1621 if (game
[gindex
].mode
!= MODE_PLAY
|| !game
[gindex
].htotal
)
1624 history_previous(&game
[gindex
], (count
) ? count
* 2 : 2, &crow
, &ccol
);
1625 oldhistorytotal
= game
[gindex
].htotal
;
1626 game
[gindex
].htotal
= game
[gindex
].hindex
;
1628 if (status
.engine
== CRAFTY
)
1629 SEND_TO_ENGINE("read %s\n", config
.fifo
);
1631 SEND_TO_ENGINE("\npgnload %s\n", config
.fifo
);
1633 update_history_window(game
[gindex
]);
1636 if ((tmp
= get_input(GAME_LOAD_TITLE
, NULL
, 1, 1,
1637 BROWSER_PROMPT
, browse_directory
, NULL
,
1641 tmp
= tilde_expand(tmp
);
1643 if (parse_pgn_file(tmp
))
1646 gindex
= gtotal
- 1;
1647 strncpy(loadfile
, tmp
, sizeof(loadfile
));
1648 init_history(&game
[gindex
]);
1649 update_all(game
[gindex
]);
1650 update_tag_window(game
[gindex
].tag
);
1657 n
= message(NULL
, GAME_SAVE_MULTI_PROMPT
, "%s",
1658 GAME_SAVE_MULTI_TEXT
);
1665 update_status_notify(game
[gindex
], "%s", NOTIFY_SAVE_ABORTED
);
1670 if ((tmp
= get_input(GAME_SAVE_TITLE
, loadfile
, 1, 1,
1671 BROWSER_PROMPT
, browse_directory
, NULL
,
1672 '\t', -1)) == NULL
) {
1673 update_status_notify(game
[gindex
], "%s", NOTIFY_SAVE_ABORTED
);
1677 tmp
= tilde_expand(tmp
);
1679 if (strstr(tmp
, ".") == NULL
&& compression_cmd(tmp
, 0)
1681 snprintf(tfile
, sizeof(tfile
), "%s.pgn", tmp
);
1685 if (save_pgn(tmp
, 0, x
)) {
1686 update_status_notify(game
[gindex
], "%s", NOTIFY_SAVE_FAILED
);
1690 update_status_notify(game
[gindex
], "%s", NOTIFY_SAVED
);
1691 update_all(game
[gindex
]);
1697 n
= help(GAME_HELP_INDEX_TITLE
,
1698 GAME_HELP_INDEX_PROMPT
, mainhelp
);
1702 help(GAME_HELP_HISTORY_TITLE
, ANYKEY
, historyhelp
);
1705 help(GAME_HELP_PLAY_TITLE
, ANYKEY
, playhelp
);
1708 help(GAME_HELP_EDIT_TITLE
, ANYKEY
, edithelp
);
1711 help(GAME_HELP_GAME_TITLE
, ANYKEY
, gamehelp
);
1723 if (cmessage(NULL
, YESNO
, "%s", GAME_NEW_PROMPT
) != 'y')
1727 game
[gindex
].mode
= MODE_PLAY
;
1729 game
[gindex
].sp
.icon
= 0;
1736 reset_history(game
[gindex
]);
1737 parse_pgn_file(NULL
);
1740 game
[gindex
].wcaptures
= game
[gindex
].bcaptures
= 0;
1741 crow
= (game
[gindex
].side
== WHITE
) ? 2 : 7;
1744 if (!noengine
&& (status
.engine
== ENGINE_OFFLINE
||
1745 engine_initialized
== 0)) {
1746 if (start_chess_engine() < 0)
1750 SEND_TO_ENGINE("\nnew\n");
1751 set_engine_defaults();
1752 status
.engine
= ENGINE_READY
;
1753 update_status_notify(game
[gindex
], NULL
);
1754 update_all(game
[gindex
]);
1755 update_tag_window(game
[gindex
].tag
);
1760 keypad(boardw
, TRUE
);
1765 if (status
.engine
== ENGINE_THINKING
)
1768 if (status
.engine
== ENGINE_OFFLINE
)
1771 if ((tmp
= get_input_str_clear(ENGINE_CMD_TITLE
, NULL
))
1773 SEND_TO_ENGINE("%s\n", tmp
);
1777 game
[gindex
].sp
.icon
= game
[gindex
].sp
.row
= game
[gindex
].sp
.col
= 0;
1778 markend
= markstart
= 0;
1782 update_status_notify(game
[gindex
], NULL
);
1785 if (config
.validmoves
)
1786 reset_valid_moves(game
[gindex
].b
);
1793 count
= count
* 10 + n
;
1797 update_status_notify(game
[gindex
], "Repeat %i", count
);
1800 if (game
[gindex
].mode
== MODE_HISTORY
) {
1801 history_next(&game
[gindex
], (count
> 0) ?
1802 config
.jumpcount
* count
* movestep
:
1803 config
.jumpcount
* movestep
, &crow
, &ccol
);
1804 update_all(game
[gindex
]);
1809 if (sp.icon && config.validmoves) {
1810 get_valid_cursor(board, UP, (count) ? count : 1,
1811 &crow, &ccol, minr, maxr, minc, maxc);
1828 if (game
[gindex
].mode
== MODE_HISTORY
) {
1829 history_previous(&game
[gindex
], (count
) ?
1830 config
.jumpcount
* count
* movestep
:
1831 config
.jumpcount
* movestep
, &crow
, &ccol
);
1832 update_all(game
[gindex
]);
1837 if (sp.icon && config.validmoves) {
1838 get_valid_cursor(board, DOWN, (count) ? count : 1,
1839 &crow, &ccol, minr, maxr, minc, maxc);
1847 update_status_notify(game
[gindex
], NULL
);
1857 if (game
[gindex
].mode
== MODE_HISTORY
) {
1858 history_previous(&game
[gindex
], (count
) ?
1859 count
* movestep
: movestep
, &crow
, &ccol
);
1860 update_all(game
[gindex
]);
1865 if (sp.icon && config.validmoves) {
1866 get_valid_cursor(board, LEFT, (count) ? count : 1,
1867 &crow, &ccol, minr, maxr, minc, maxc);
1884 if (game
[gindex
].mode
== MODE_HISTORY
) {
1885 history_next(&game
[gindex
], (count
) ? count
* movestep
1886 : movestep
, &crow
, &ccol
);
1887 update_all(game
[gindex
]);
1892 if (sp.icon && config.validmoves) {
1893 get_valid_cursor(board, RIGHT, (count) ? count : 1,
1894 &crow, &ccol, minr, maxr, minc, maxc);
1911 if (game
[gindex
].mode
== MODE_HISTORY
)
1914 if (game
[gindex
].mode
== MODE_EDIT
)
1915 switch_turn(&game
[gindex
]);
1918 SEND_TO_ENGINE("\nswitch\n");
1919 switch_side(&game
[gindex
]);
1920 update_status_window(game
[gindex
]);
1923 if (!editmode
&& game
[gindex
].mode
== MODE_HISTORY
) {
1929 update_history_window(game
[gindex
]);
1933 if (!noengine
&& (status
.engine
== ENGINE_OFFLINE
||
1934 !engine_initialized
) && !editmode
) {
1935 if (start_chess_engine() < 0) {
1936 game
[gindex
].sp
.icon
= 0;
1943 wtimeout(boardw
, 70);
1945 if (game
[gindex
].sp
.icon
|| (!editmode
&& status
.engine
== ENGINE_THINKING
)) {
1950 game
[gindex
].sp
.icon
= mvwinch(boardw
, ROWTOMATRIX(crow
),
1951 COLTOMATRIX(ccol
)+1) & A_CHARTEXT
;
1953 if (game
[gindex
].sp
.icon
== ' ') {
1954 game
[gindex
].sp
.icon
= 0;
1958 if (!editmode
&& ((islower(game
[gindex
].sp
.icon
) &&
1959 game
[gindex
].turn
!= BLACK
) ||
1960 (isupper(game
[gindex
].sp
.icon
) &&
1961 game
[gindex
].turn
!= WHITE
))) {
1962 message(NULL
, ANYKEY
, "%s", E_SELECT_TURN
);
1963 game
[gindex
].sp
.icon
= 0;
1967 game
[gindex
].sp
.row
= crow
;
1968 game
[gindex
].sp
.col
= ccol
;
1970 if (!editmode
&& config
.validmoves
) {
1971 get_valid_moves(&game
[gindex
],
1972 piece_to_int(game
[gindex
].sp
.icon
),
1973 game
[gindex
].sp
.row
, game
[gindex
].sp
.col
, &minr
,
1974 &maxr
, &minc
, &maxc
);
1976 number_valid_moves(board, sp.row, sp.col);
1980 if (game
[gindex
].mode
== MODE_PLAY
)
1985 pushkey
= count
= 0;
1986 update_status_notify(game
[gindex
], NULL
);
1988 if (!editmode
&& game
[gindex
].mode
== MODE_HISTORY
)
1991 if (status
.engine
== ENGINE_THINKING
) {
1996 if (!game
[gindex
].sp
.icon
)
1999 game
[gindex
].sp
.destrow
= crow
;
2000 game
[gindex
].sp
.destcol
= ccol
;
2003 edit_board(&game
[gindex
]);
2004 game
[gindex
].sp
.icon
= game
[gindex
].sp
.row
= game
[gindex
].sp
.col
= 0;
2008 if (move_to_engine(&game
[gindex
])) {
2009 if (config
.validmoves
)
2010 reset_valid_moves(game
[gindex
].b
);
2012 if (TEST_FLAG(game
[gindex
].flags
, GF_GAMEOVER
)) {
2013 CLEAR_FLAG(game
[gindex
].flags
, GF_GAMEOVER
);
2014 SET_FLAG(game
[gindex
].flags
, GF_MODIFIED
);
2033 void usage(const char *pn
, int ret
)
2037 for (i
= 0; cmdlinehelp
[i
]; i
++)
2038 fputs(cmdlinehelp
[i
], stderr
);
2043 void catch_signal(int which
)
2055 cmessage(NULL
, ANYKEY
, "%s", E_BROKEN_PIPE
);
2064 keypad(boardw
, TRUE
);
2071 int main(int argc
, char *argv
[])
2075 char buf
[FILENAME_MAX
];
2076 char datadir
[FILENAME_MAX
];
2077 int ret
= EXIT_SUCCESS
;
2078 int validate
= 0, validate_and_save
= 0;
2080 if ((config
.pwd
= getpwuid(getuid())) == NULL
)
2081 err(EXIT_FAILURE
, "getpwuid()");
2083 snprintf(datadir
, sizeof(datadir
), "%s/.cboard", config
.pwd
->pw_dir
);
2084 snprintf(buf
, sizeof(buf
), "%s/cc.data", datadir
);
2085 config
.ccfile
= strdup(buf
);
2086 snprintf(buf
, sizeof(buf
), "%s/nag.data", datadir
);
2087 config
.nagfile
= strdup(buf
);
2088 snprintf(buf
, sizeof(buf
), "%s/agony.data", datadir
);
2089 config
.agonyfile
= strdup(buf
);
2090 snprintf(buf
, sizeof(buf
), "%s/config", datadir
);
2091 config
.configfile
= strdup(buf
);
2092 snprintf(buf
, sizeof(buf
), "%s/fifo", datadir
);
2093 config
.fifo
= strdup(buf
);
2094 snprintf(buf
, sizeof(buf
), "%s/tmpfile", datadir
);
2095 config
.tmpfile
= strdup(buf
);
2097 if (stat(datadir
, &st
) == -1) {
2098 if (errno
== ENOENT
) {
2099 if (mkdir(datadir
, 0755) == -1)
2100 err(EXIT_FAILURE
, "%s", datadir
);
2103 err(EXIT_FAILURE
, "%s", datadir
);
2108 if (!S_ISDIR(st
.st_mode
))
2109 errx(EXIT_FAILURE
, "%s: %s", datadir
, E_NOTADIR
);
2111 if (access(config
.fifo
, R_OK
) == -1 && errno
== ENOENT
) {
2112 if (mkfifo(config
.fifo
, 0600) == -1)
2113 err(EXIT_FAILURE
, "%s", config
.fifo
);
2119 while ((opt
= getopt(argc
, argv
, "EDNVtShp:vu:e:f:i:")) != -1) {
2121 while ((opt
= getopt(argc
, argv
, "ENVtShp:vu:e:f:i:")) != -1) {
2128 save_custom_tags
= 1;
2131 config
.stoponerror
= 1;
2137 validate_and_save
= 1;
2149 while ((tmp
= strsep(&optarg
, ":")) != NULL
) {
2152 config
.ics_user
= optarg
;
2155 config
.ics_passwd
= optarg
;
2158 usage(argv
[0], EXIT_FAILURE
);
2165 while ((tmp
= strsep(&optarg
, ":")) != NULL
) {
2168 strncpy(config
.ics_server
, tmp
,
2169 sizeof(config
.ics_server
));
2172 if (!isinteger(tmp
))
2173 usage(argv
[0], EXIT_FAILURE
);
2175 config
.ics_port
= atoi(tmp
);
2178 usage(argv
[0], EXIT_FAILURE
);
2183 printf("%s (%s)\n%s\n", PACKAGE_STRING
, curses_version(),
2187 filetype
= PGN_FILE
;
2188 strncpy(loadfile
, optarg
, sizeof(loadfile
));
2191 filetype
= FEN_FILE
;
2192 strncpy(loadfile
, optarg
, sizeof(loadfile
));
2195 filetype
= EPD_FILE
;
2196 strncpy(loadfile
, optarg
, sizeof(loadfile
));
2200 usage(argv
[0], EXIT_SUCCESS
);
2204 if ((validate
|| validate_and_save
) && !*loadfile
)
2205 usage(argv
[0], EXIT_FAILURE
);
2207 if (access(config
.configfile
, R_OK
) == 0)
2208 parse_rcfile(config
.configfile
);
2210 signal(SIGPIPE
, catch_signal
);
2211 signal(SIGCONT
, catch_signal
);
2212 signal(SIGSTOP
, catch_signal
);
2213 signal(SIGINT
, catch_signal
);
2219 ret
= parse_pgn_file(loadfile
);
2222 //ret = parse_fen_file(loadfile);
2224 case EPD_FILE
: // Not implemented.
2227 // No file specified. Empty game.
2228 ret
= parse_pgn_file(NULL
);
2232 if (validate
|| validate_and_save
) {
2233 if (validate_and_save
) {
2236 for (i
= 0; i
< gtotal
; i
++)
2237 pgn_dumpgame(stdout
, &game
[i
], i
, 0);
2246 if (initscr() == NULL
)
2247 errx(EXIT_FAILURE
, "%s", E_INITCURSES
);
2249 curses_initialized
= 1;
2251 if (has_colors() == TRUE
&& start_color() == OK
)
2254 boardw
= newwin(BOARD_HEIGHT
, BOARD_WIDTH
, 0, COLS
- BOARD_WIDTH
);
2255 boardp
= new_panel(boardw
);
2256 historyw
= newwin(HISTORY_HEIGHT
, HISTORY_WIDTH
, LINES
- HISTORY_HEIGHT
,
2257 COLS
- HISTORY_WIDTH
);
2258 historyp
= new_panel(historyw
);
2259 statusw
= newwin(STATUS_HEIGHT
, STATUS_WIDTH
, LINES
- STATUS_HEIGHT
, 0);
2260 statusp
= new_panel(statusw
);
2261 tagw
= newwin(TAG_HEIGHT
, TAG_WIDTH
, 0, 0);
2262 tagp
= new_panel(tagw
);
2263 keypad(boardw
, TRUE
);
2264 // leaveok(boardw, TRUE);
2265 leaveok(tagw
, TRUE
);
2266 leaveok(statusw
, TRUE
);
2267 leaveok(historyw
, TRUE
);
2272 wbkgd(boardw
, CP_BOARD_WINDOW
);
2273 wbkgd(statusw
, CP_STATUS_WINDOW
);
2274 draw_window_title(statusw
, STATUS_WINDOW_TITLE
, STATUS_WIDTH
,
2275 CP_STATUS_TITLE
, CP_STATUS_BORDER
);
2276 wbkgd(tagw
, CP_TAG_WINDOW
);
2277 draw_window_title(tagw
, TAG_WINDOW_TITLE
, TAG_WIDTH
, CP_TAG_TITLE
,
2279 wbkgd(historyw
, CP_HISTORY_WINDOW
);
2280 draw_window_title(historyw
, HISTORY_WINDOW_TITLE
, HISTORY_WIDTH
,
2281 CP_HISTORY_TITLE
, CP_HISTORY_BORDER
);
2289 del_panel(historyp
);