Autotools portability fixes and cleanups.
[cboard.git] / src / rcfile.c
blob5a710a25406f6865e23746014c08d1b8e93c69ae
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2011 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
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <errno.h>
30 #include <err.h>
32 #ifdef HAVE_NCURSES_H
33 #include <ncurses.h>
34 #elif defined(HAVE_CURSES_H)
35 #include <curses.h>
36 #endif
38 #ifdef HAVE_STRINGS_H
39 #include <strings.h>
40 #endif
42 #include "chess.h"
43 #include "conf.h"
44 #include "misc.h"
45 #include "colors.h"
46 #include "keys.h"
47 #include "rcfile.h"
49 #ifdef WITH_DMALLOC
50 #include <dmalloc.h>
51 #endif
53 static int attributes(const char *filename, int line, char *str)
55 char *tmp;
56 int attrs = 0;
58 while ((tmp = strsep(&str, ",")) != NULL) {
59 if (strcasecmp(tmp, "BOLD") == 0)
60 attrs |= A_BOLD;
61 else if (strcasecmp(tmp, "REVERSE") == 0)
62 attrs |= A_REVERSE;
63 else if (strcasecmp(tmp, "NONE") == 0)
64 attrs |= A_NORMAL;
65 else if (strcasecmp(tmp, "DIM") == 0)
66 attrs |= A_DIM;
67 else if (strcasecmp(tmp, "STANDOUT") == 0)
68 attrs |= A_STANDOUT;
69 else if (strcasecmp(tmp, "UNDERLINE") == 0)
70 attrs |= A_UNDERLINE;
71 else if (strcasecmp(tmp, "BLINK") == 0)
72 attrs |= A_BLINK;
73 else if (strcasecmp(tmp, "INVISIBLE") == 0)
74 attrs |= A_INVIS;
75 else
76 errx(EXIT_FAILURE, "%s(%i): invalid attribute \"%s\"", filename,
77 line, tmp);
80 return attrs;
83 static short color_name(const char *filename, int line, const char *color)
85 if (strcasecmp(color, "BLACK") == 0)
86 return COLOR_BLACK;
87 else if (strcasecmp(color, "WHITE") == 0)
88 return COLOR_WHITE;
89 else if (strcasecmp(color, "GREEN") == 0)
90 return COLOR_GREEN;
91 else if (strcasecmp(color, "YELLOW") == 0)
92 return COLOR_YELLOW;
93 else if (strcasecmp(color, "MAGENTA") == 0)
94 return COLOR_MAGENTA;
95 else if (strcasecmp(color, "BLUE") == 0)
96 return COLOR_BLUE;
97 else if (strcasecmp(color, "RED") == 0)
98 return COLOR_RED;
99 else if (strcasecmp(color, "CYAN") == 0)
100 return COLOR_CYAN;
101 else if (strcasecmp(color, "-") == 0)
103 else
104 errx(EXIT_FAILURE, "%s(%i): invalid color \"%s\"", filename, line,
105 color);
107 return -1;
110 static void parse_color(const char *filename, int line, const char *str,
111 struct color_s *c)
113 char fg[16], bg[16], attr[64], nattr[64];
114 int n;
116 if ((n = sscanf(str, "%[a-zA-Z-] %[a-zA-Z-] %[a-zA-Z,-] %[a-zA-Z,-]", fg, bg,
117 attr, nattr)) < 2)
118 errx(EXIT_FAILURE, "%s(%i): parse error", filename, line);
120 if ((n = color_name(filename, line, fg)) >= 0)
121 c->fg = n;
123 if ((n = color_name(filename, line, bg)) >= 0)
124 c->bg = n;
126 c->attrs = c->nattrs = 0;
128 if (n > 2)
129 c->attrs = attributes(filename, line, attr);
131 if (n > 3)
132 c->nattrs = attributes(filename, line, nattr);
135 static int on_or_off(const char *filename, int lines, const char *str)
137 if (strcasecmp(str, "on") == 0 || strcasecmp(str, "1") == 0 ||
138 strcasecmp(str, "yes") == 0 || strcasecmp(str, "true") == 0)
139 return 1;
141 if (strcasecmp(str, "off") == 0 || strcasecmp(str, "0") == 0 ||
142 strcasecmp(str, "no") == 0 || strcasecmp(str, "false") == 0)
143 return 0;
145 errx(EXIT_FAILURE, "%s(%i): invalid value \"%s\"", filename, lines, str);
148 void copydatafile(const char *dst, const char *src)
150 FILE *fp, *ofp;
151 char buf[LINE_MAX], *s;
153 snprintf(buf, sizeof(buf), "%s/%s", DATA_PATH, src);
155 if ((fp = fopen(buf, "r")) == NULL) {
156 if (errno != ENOENT)
157 warn("%s", buf);
158 return;
161 if ((ofp = fopen(dst, "w+")) == NULL) {
162 fclose(fp);
163 warn("%s", dst);
164 return;
167 while ((s = fgets(buf, sizeof(buf), fp)) != NULL)
168 fprintf(ofp, "%s", s);
170 fclose(fp);
171 fclose(ofp);
174 static char *fancy_key_name(int c)
176 static char buf[12];
177 char *p;
179 strncpy(buf, keyname(c), sizeof(buf));
180 p = buf;
182 if (*p == '^' && *(p + 1) == '[')
183 return "Escape";
185 if (*p == '^' && *(p + 1) == 'J')
186 return "Enter";
188 if (strncasecmp(p, "KEY_", 4) == 0) {
189 for (p = buf; *p; p++)
190 *p = tolower(*p);
192 p = buf;
193 p += 4;
195 if (*p == 'f') {
196 char *t = buf + 4;
198 p += 2;
200 while (isdigit(*p))
201 *++t = *p++;
203 *++t = 0;
204 p = buf + 4;
206 else if (strcmp(p, "ppage") == 0)
207 return "PgUp";
208 else if (strcmp(p, "npage") == 0)
209 return "PgDown";
211 *p = toupper(*p);
212 return p;
215 if (*p == ' ')
216 return "Space";
218 return p;
221 void add_key_binding(struct key_s ***dst, key_func *func, int c, char *desc,
222 int repeat)
224 int i = 0;
225 struct key_s **k = *dst;
227 if (k)
228 for (i = 0; k[i]; i++);
230 k = Realloc(k, (i + 2) * sizeof(struct key_s *));
231 k[i] = Calloc(1, sizeof(struct key_s));
232 k[i]->f = func;
233 k[i]->c = c;
234 k[i]->r = repeat;
235 k[i]->key = strdup(fancy_key_name(c));
237 if (desc)
238 k[i]->d = strdup(desc);
240 i++;
241 k[i] = NULL;
242 *dst = k;
245 void set_default_keys()
247 add_key_binding(&history_keys, do_history_jump_next, KEY_UP, "history jump next", 1);
248 add_key_binding(&history_keys, do_history_jump_prev, KEY_DOWN, "history jump previous", 1);
249 add_key_binding(&history_keys, do_history_next, KEY_RIGHT, "next move", 1);
250 add_key_binding(&history_keys, do_history_prev, KEY_LEFT, "previous move", 1);
251 add_key_binding(&history_keys, do_history_half_move_toggle, ' ', "toggle half move (ply) stepping", 0);
252 add_key_binding(&history_keys, do_history_jump, 'j', "jump to move number", 1);
253 add_key_binding(&history_keys, do_history_find_new, '/', "new move text expression", 0);
254 add_key_binding(&history_keys, do_history_find_next, ']', "find next move text expression", 1);
255 add_key_binding(&history_keys, do_history_find_prev, '[', "find previous move text expression", 1);
256 add_key_binding(&history_keys, do_history_annotate, CTRL('a'), "annotate the previous move", 0);
257 add_key_binding(&history_keys, do_history_rav_next, '+', "next variation of the previous move", 0);
258 add_key_binding(&history_keys, do_history_rav_prev, '-', "previous variation of the previous move", 0);
259 add_key_binding(&history_keys, do_history_menu, 'M', "move history tree", 0);
260 add_key_binding(&history_keys, do_history_help, KEY_F(1), "more help", 0);
261 add_key_binding(&history_keys, do_history_help, CTRL('g'), NULL, 0);
262 add_key_binding(&history_keys, do_history_toggle, 'h', "exit history mode", 0);
264 add_key_binding(&edit_keys, do_edit_select, ' ', "select piece for movement", 0);
265 add_key_binding(&edit_keys, do_edit_commit, '\n', "commit selected piece", 0);
266 add_key_binding(&edit_keys, do_edit_cancel_selected, KEY_ESCAPE, "cancel selected piece", 0);
267 add_key_binding(&edit_keys, do_edit_delete, 'd', "remove the piece under the cursor", 0);
268 add_key_binding(&edit_keys, do_edit_insert, 'i', "insert piece", 0);
269 add_key_binding(&edit_keys, do_edit_toggle_castle, 'c', "toggle castling availability", 0);
270 add_key_binding(&edit_keys, do_edit_enpassant, 'p', "toggle enpassant square", 0);
271 add_key_binding(&edit_keys, do_edit_switch_turn, 'w', "toggle turn", 0);
272 add_key_binding(&edit_keys, do_edit_help, KEY_F(1), "more help", 0);
273 add_key_binding(&history_keys, do_edit_help, CTRL('g'), NULL, 0);
274 add_key_binding(&edit_keys, do_edit_exit, 'e', "exit edit mode", 0);
276 add_key_binding(&play_keys, do_play_select, ' ', "select piece for movement", 0);
277 add_key_binding(&play_keys, do_play_commit, '\n', "commit selected piece", 0);
278 add_key_binding(&play_keys, do_play_cancel_selected, KEY_ESCAPE, "cancel selected piece", 0);
279 add_key_binding(&play_keys, do_play_set_clock, 'C', "set clock", 0);
280 add_key_binding(&play_keys, do_play_switch_turn, 'w', "switch turn", 0);
281 add_key_binding(&play_keys, do_play_undo, 'u', "undo previous move", 1);
282 add_key_binding(&play_keys, do_play_go, 'g', "force the chess engine to make the next move", 0);
283 add_key_binding(&play_keys, do_play_send_command, '|', "send a command to the chess engine", 0);
284 add_key_binding(&play_keys, do_play_toggle_engine, 'E', "toggle engine/engine play", 0);
285 add_key_binding(&play_keys, do_play_toggle_human, 'H', "toggle human/human play", 0);
286 add_key_binding(&play_keys, do_play_toggle_pause, 'p', "toggle pausing of this game", 0);
287 add_key_binding(&play_keys, do_play_history_mode, 'h', "enter history mode", 0);
288 add_key_binding(&play_keys, do_play_edit_mode, 'e', "enter edit mode", 0);
289 add_key_binding(&play_keys, do_play_help, KEY_F(1), "more help", 0);
290 add_key_binding(&play_keys, do_play_help, CTRL('g'), NULL, 0);
292 add_key_binding(&global_keys, do_global_tag_edit, CTRL('t'), "edit roster tags", 0);
293 add_key_binding(&global_keys, do_global_tag_view, 't', "view roster tags", 0);
294 add_key_binding(&global_keys, do_global_find_new, '?', "new find game expression", 0);
295 add_key_binding(&global_keys, do_global_find_next, '}', "find next game", 1);
296 add_key_binding(&global_keys, do_global_find_prev, '{', "find previous game", 1);
297 add_key_binding(&global_keys, do_global_new_game, CTRL('n'), "new game or round", 0);
298 add_key_binding(&global_keys, do_global_new_all, CTRL('k'), "new game from scratch", 0);
299 add_key_binding(&global_keys, do_global_copy_game, CTRL('i'), "copy current game", 0);
300 add_key_binding(&global_keys, do_global_next_game, '>', "next game", 1);
301 add_key_binding(&global_keys, do_global_prev_game, '<', "previous game", 1);
302 add_key_binding(&global_keys, do_global_game_jump, 'J', "jump to game", 1);
303 add_key_binding(&global_keys, do_global_toggle_delete, 'X', "toggle delete flag", 1);
304 add_key_binding(&global_keys, do_global_delete_game, CTRL('X'), "delete the current or flagged games", 0);
305 add_key_binding(&global_keys, do_global_resume_game, CTRL('r'), "load a PGN file", 0);
306 add_key_binding(&global_keys, do_global_save_game, 's', "save game", 0);
307 add_key_binding(&global_keys, do_global_toggle_board_details, CTRL('d'), "toggle board details", 0);
308 add_key_binding(&global_keys, do_global_toggle_strict_castling, CTRL('p'), "toggle strict castling", 0);
309 add_key_binding(&global_keys, do_global_toggle_engine_window, 'W', "toggle chess engine IO window", 0);
310 #ifdef WITH_LIBPERL
311 add_key_binding(&global_keys, do_global_perl, CTRL('O'), "Call PERL subroutine", 0);
312 #endif
313 add_key_binding(&global_keys, do_global_about, KEY_F(10), "version information", 0);
314 add_key_binding(&global_keys, do_global_quit, 'Q', "quit", 0);
317 void set_config_defaults()
319 struct stat st;
321 config.pattern = strdup("*.[Pp][Gg][Nn]*");
322 config.engine_cmd = strdup("gnuchess --xboard");
323 config.engine_protocol = 1;
324 config.jumpcount = 5;
325 config.linegraphics = 1;
326 config.saveprompt = 1;
327 config.deleteprompt = 1;
328 config.validmoves = 1;
329 config.details = 1;
331 set_default_colors();
333 if (stat(config.nagfile, &st) == -1) {
334 if (errno == ENOENT)
335 copydatafile(config.nagfile, "nag.data");
336 else
337 warn("%s", config.nagfile);
340 if (stat(config.ccfile, &st) == -1) {
341 if (errno == ENOENT)
342 copydatafile(config.ccfile, "cc.data");
343 else
344 warn("%s", config.ccfile);
348 static void update_key(struct key_s **dst, struct custom_key_s config_key,
349 int c, char *desc)
351 int i;
353 for (i = 0; dst[i]; i++) {
354 if (dst[i]->f == config_key.func) {
355 dst[i]->c = c;
357 if (dst[i]->key)
358 free(dst[i]->key);
360 dst[i]->key = strdup(fancy_key_name(c));
362 if (desc && dst[i]->d)
363 free(dst[i]->d);
365 if (desc)
366 dst[i]->d = strdup(desc);
368 goto done;
372 add_key_binding(&dst, config_key.func, c, (desc) ? desc : "no description",
373 config_key.r);
375 done:
376 return;
379 static int parse_key(const char *filename, int lines, char **key)
381 char *p = *key;
382 char *orig = *key;
383 int c = 0;
385 if (!key || !key[0])
386 return 0;
388 if (*p == '\"') {
389 if (orig[strlen(orig) - 1] != '\"')
390 errx(EXIT_FAILURE, "%s(%i): unbalanced quotes", filename, lines);
392 p++;
393 orig[strlen(orig) - 1] = 0;
396 if (*p == '<') {
397 p++;
399 if (strncasecmp(p, "up", 2) == 0) {
400 c = KEY_UP;
401 p += 2;
403 else if (strncasecmp(p, "down", 4) == 0) {
404 c = KEY_DOWN;
405 p += 4;
407 else if (strncasecmp(p, "left", 4) == 0) {
408 c = KEY_LEFT;
409 p += 4;
411 else if (strncasecmp(p, "right", 5) == 0) {
412 c = KEY_RIGHT;
413 p += 5;
415 else if (strncasecmp(p, "home", 4) == 0) {
416 c = KEY_HOME;
417 p += 4;
419 else if (strncasecmp(p, "end", 3) == 0) {
420 c = KEY_END;
421 p += 3;
423 else if (strncasecmp(p, "delete", 6) == 0) {
424 c = KEY_DC;
425 p += 6;
427 else if (strncasecmp(p, "pgup", 4) == 0) {
428 c = KEY_PPAGE;
429 p += 4;
431 else if (strncasecmp(p, "pgdn", 4) == 0) {
432 c = KEY_NPAGE;
433 p += 4;
435 else if (strncasecmp(p, "insert", 5) == 0) {
436 c = KEY_IC;
437 p += 5;
439 else if (strncasecmp(p, "space", 5) == 0) {
440 c = ' ';
441 p += 5;
443 else if (strncasecmp(p, "escape", 6) == 0) {
444 c = KEY_ESCAPE;
445 p += 6;
447 else if (strncasecmp(p, "enter", 5) == 0) {
448 c = '\n';
449 p += 5;
451 else if (*p == '^') {
452 p++;
453 c = CTRL(*p++);
455 else if (*p == 'F' || *p == 'f') {
456 c = KEY_F(atoi(++p));
457 p += integer_len(atoi(p));
460 if (!c)
461 c = *p++;
463 if (*p++ != '>')
464 errx(EXIT_FAILURE, "%s(%i): parse error \"%s\"", filename, lines,
465 orig);
467 else if (*p == '\\') {
468 p++;
469 c = *p++;
471 else
472 c = *p++;
474 orig += strlen(orig) - strlen(p);
475 *key = orig;
476 return c;
479 static void parse_key_binding(const char *filename, int lines, char *val)
481 char mode[64], key[16], func[64], desc[64];
482 int n;
483 int m = 0;
484 int c = 0;
485 int f;
486 int i;
487 char *p;
489 n = sscanf(val, "%s %s %s %s", mode, key, func, desc);
491 if (n < 3)
492 errx(EXIT_FAILURE, "%s(%i): too few arguments", filename, lines);
494 if (strcasecmp(mode, "history") == 0)
495 m = MODE_HISTORY;
496 else if (strcasecmp(mode, "play") == 0)
497 m = MODE_PLAY;
498 else if (strcasecmp(mode, "edit") == 0)
499 m = MODE_EDIT;
500 else
501 errx(EXIT_FAILURE, "%s(%i): invalid game mode \"%s\"", filename, lines,
502 mode);
504 p = key;
505 c = parse_key(filename, lines, &p);
507 if (m != -1) {
508 for (i = 0; global_keys[i]; i++) {
509 if (global_keys[i]->c == c)
510 errx(EXIT_FAILURE, "%s(%i): key \"%s\" conflicts with a global "
511 "key", filename, lines, key);
515 for (f = -2, i = 0; config_keys[i].name; i++) {
516 if (strcmp(config_keys[i].name, func) == 0 &&
517 config_keys[i].mode == m) {
518 f = i;
519 break;
523 if (f == -2)
524 errx(EXIT_FAILURE, "%s(%i): invalid command \"%s\"", filename, lines,
525 func);
527 switch (m) {
528 case MODE_PLAY:
529 update_key(play_keys, config_keys[f], c, (n > 3) ? desc : NULL);
530 break;
531 case MODE_HISTORY:
532 update_key(history_keys, config_keys[f], c, (n > 3) ? desc : NULL);
533 break;
534 case MODE_EDIT:
535 update_key(edit_keys, config_keys[f], c, (n > 3) ? desc : NULL);
536 break;
537 default:
538 update_key(global_keys, config_keys[f], c, (n > 3) ? desc : NULL);
539 break;
543 static void parse_macro(const char *filename, int lines, char *val)
545 char mode[16], key[8], keys[256] = {0};
546 int n;
547 int m;
548 int c;
549 int i = 0;
550 char *p;
552 n = sscanf(val, "%s %s %255c", mode, key, keys);
554 if (n != 3)
555 errx(EXIT_FAILURE, "%s(%i): too few arguments", filename, lines);
557 if (strcasecmp(mode, "history") == 0)
558 m = MODE_HISTORY;
559 else if (strcasecmp(mode, "play") == 0)
560 m = MODE_PLAY;
561 else if (strcasecmp(mode, "edit") == 0)
562 m = MODE_EDIT;
563 else if (strcasecmp(mode, "any") == 0)
564 m = -1;
565 else
566 errx(EXIT_FAILURE, "%s(%i): invalid game mode \"%s\"", filename, lines,
567 mode);
569 p = key;
570 c = parse_key(filename, lines, &p);
572 if (macros)
573 for (i = 0; macros[i]; i++);
575 macros = Realloc(macros, (i + 2) * sizeof(struct macro_s));
576 macros[i] = Calloc(1, sizeof(struct macro_s));
577 macros[i]->c = c;
578 macros[i]->mode = m;
579 p = keys;
581 while ((c = parse_key(filename, lines, &p)) != 0) {
582 macros[i]->keys = Realloc(macros[i]->keys, (macros[i]->total + 2) *
583 sizeof(int));
584 macros[i]->keys[macros[i]->total++] = c;
587 macros[++i] = NULL;
590 void parse_rcfile(const char *filename)
592 FILE *fp;
593 char *line, buf[LINE_MAX];
594 int lines = 0;
595 char *altengine = NULL;
596 int init = 0;
597 int k = 0;
598 int c;
600 if ((fp = fopen(filename, "r")) == NULL)
601 err(EXIT_FAILURE, "%s", filename);
603 while ((line = fgets(buf, sizeof(buf), fp)) != NULL) {
604 int n;
605 char var[30], val[LINE_MAX - sizeof(var) - 1];
606 char token[MAX_PGN_LINE_LEN + 1], value[MAX_PGN_LINE_LEN + 1];
607 char *p;
609 lines++;
610 line = trim(line);
612 if (!line[0] || line[0] == '#')
613 continue;
615 if ((n = sscanf(line, "%s %[^\n]", var, val)) != 2)
616 errx(EXIT_FAILURE, "%s(%i): parse error %i", filename, lines,n);
618 p = strdup(trim(val));
619 strncpy(val, p, sizeof(val));
620 free(p);
621 p = strdup(trim(var));
622 strncpy(var, p, sizeof(var));
623 free(p);
625 if (strcmp(var, "jump_count") == 0) {
626 if (!isinteger(val))
627 errx(EXIT_FAILURE, "%s(%i): value is not an integer", filename,
628 lines);
630 config.jumpcount = atoi(val);
632 else if (strcmp(var, "engine_init") == 0) {
633 config.einit = Realloc(config.einit, (init + 2) * sizeof(char *));
634 config.einit[init++] = strdup(val);
635 config.einit[init] = NULL;
637 else if (strcmp(var, "pattern") == 0) {
638 free(config.pattern);
639 config.pattern = strdup(val);
641 else if (strcmp(var, "mpl") == 0) {
642 if (!isinteger(val))
643 errx(EXIT_FAILURE, "%s(%i): value is not an integer", filename,
644 lines);
645 pgn_config_set(PGN_MPL, atoi(val));
647 else if (strcmp(var, "stop_on_error") == 0)
648 pgn_config_set(PGN_STOP_ON_ERROR, on_or_off(filename, lines, val));
649 else if (strcmp(var, "tag") == 0) {
650 if ((n = sscanf(val, "%s %s ", token, value)) < 1 ||
651 n > 2)
652 errx(EXIT_FAILURE, "%s(%i): invalid value \"%s\"", filename,
653 lines, val);
655 if (n == 1)
656 value[0] = 0;
657 else {
658 p = val + strlen(token);
659 strncpy(value, p, sizeof(value));
662 for (n = 0; n < strlen(token); n++) {
663 if (!isalnum(token[n]) && token[n] != '_')
664 errx(EXIT_FAILURE,
665 "%s(%i): token names must match 0-9A-Za-z_.",
666 filename, lines);
669 token[0] = toupper(token[0]);
670 pgn_tag_add(&config.tag, token, value);
672 else if (strcmp(var, "save_directory") == 0)
673 config.savedirectory = strdup(val);
674 else if (strcmp(var, "line_graphics") == 0)
675 config.linegraphics = on_or_off(filename, lines, val);
676 else if (strcmp(var, "save_prompt") == 0)
677 config.saveprompt = on_or_off(filename, lines, val);
678 else if (strcmp(var, "delete_prompt") == 0)
679 config.deleteprompt = on_or_off(filename, lines, val);
680 else if (strcmp(var, "valid_moves") == 0)
681 config.validmoves = on_or_off(filename, lines, val);
682 else if (strcmp(var, "board_details") == 0)
683 config.details = on_or_off(filename, lines, val);
684 else if (strcmp(var, "strict_castling") == 0)
685 pgn_config_set(PGN_STRICT_CASTLING, on_or_off(filename, lines, val));
686 else if (strcmp(var, "engine_cmd") == 0)
687 altengine = strdup(val);
688 else if (strcmp(var, "engine_protocol") == 0) {
689 if (!isinteger(val))
690 errx(EXIT_FAILURE, "%s(%i): value is not an integer", filename,
691 lines);
693 config.engine_protocol = atoi(val);
695 if (config.engine_protocol != 1 && config.engine_protocol != 2)
696 errx(EXIT_FAILURE, "%s(%i): invalid value", filename, lines);
698 else if (strcmp(var, "color_board_window") == 0)
699 parse_color(filename, lines, val, &config.color[CONF_BDWINDOW]);
700 else if (strcmp(var, "color_board_selected") == 0)
701 parse_color(filename, lines, val, &config.color[CONF_BSELECTED]);
702 else if (strcmp(var, "color_board_white_moves") == 0)
703 parse_color(filename, lines, val, &config.color[CONF_BMOVESW]);
704 else if (strcmp(var, "color_board_black_moves") == 0)
705 parse_color(filename, lines, val, &config.color[CONF_BMOVESB]);
706 else if (strcmp(var, "color_board_count") == 0)
707 parse_color(filename, lines, val, &config.color[CONF_BCOUNT]);
708 else if (strcmp(var, "color_board_cursor") == 0)
709 parse_color(filename, lines, val, &config.color[CONF_BCURSOR]);
710 else if (strcmp(var, "color_board_black") == 0)
711 parse_color(filename, lines, val, &config.color[CONF_BBLACK]);
712 else if (strcmp(var, "color_board_white") == 0)
713 parse_color(filename, lines, val, &config.color[CONF_BWHITE]);
714 else if (strcmp(var, "color_board_graphics") == 0)
715 parse_color(filename, lines, val, &config.color[CONF_BGRAPHICS]);
716 else if (strcmp(var, "color_board_coords") == 0)
717 parse_color(filename, lines, val, &config.color[CONF_BCOORDS]);
718 else if (strcmp(var, "color_board_castling") == 0)
719 parse_color(filename, lines, val, &config.color[CONF_BCASTLING]);
720 else if (strcmp(var, "color_board_enpassant") == 0)
721 parse_color(filename, lines, val, &config.color[CONF_BENPASSANT]);
722 else if (strcmp(var, "color_status_window") == 0)
723 parse_color(filename, lines, val, &config.color[CONF_SWINDOW]);
724 else if (strcmp(var, "color_status_title") == 0)
725 parse_color(filename, lines, val, &config.color[CONF_STITLE]);
726 else if (strcmp(var, "color_status_border") == 0)
727 parse_color(filename, lines, val, &config.color[CONF_SBORDER]);
728 else if (strcmp(var, "color_status_notify") == 0)
729 parse_color(filename, lines, val, &config.color[CONF_SNOTIFY]);
730 else if (strcmp(var, "color_status_engine") == 0)
731 parse_color(filename, lines, val, &config.color[CONF_SENGINE]);
732 else if (strcmp(var, "color_tag_window") == 0)
733 parse_color(filename, lines, val, &config.color[CONF_TWINDOW]);
734 else if (strcmp(var, "color_tag_title") == 0)
735 parse_color(filename, lines, val, &config.color[CONF_TTITLE]);
736 else if (strcmp(var, "color_tag_border") == 0)
737 parse_color(filename, lines, val, &config.color[CONF_TBORDER]);
738 else if (strcmp(var, "color_history_window") == 0)
739 parse_color(filename, lines, val, &config.color[CONF_HWINDOW]);
740 else if (strcmp(var, "color_history_title") == 0)
741 parse_color(filename, lines, val, &config.color[CONF_HTITLE]);
742 else if (strcmp(var, "color_history_border") == 0)
743 parse_color(filename, lines, val, &config.color[CONF_HBORDER]);
744 else if (strcmp(var, "color_message_window") == 0)
745 parse_color(filename, lines, val, &config.color[CONF_MWINDOW]);
746 else if (strcmp(var, "color_message_title") == 0)
747 parse_color(filename, lines, val, &config.color[CONF_MTITLE]);
748 else if (strcmp(var, "color_message_border") == 0)
749 parse_color(filename, lines, val, &config.color[CONF_MBORDER]);
750 else if (strcmp(var, "color_message_prompt") == 0)
751 parse_color(filename, lines, val, &config.color[CONF_MPROMPT]);
752 else if (strcmp(var, "color_input_window") == 0)
753 parse_color(filename, lines, val, &config.color[CONF_IWINDOW]);
754 else if (strcmp(var, "color_input_title") == 0)
755 parse_color(filename, lines, val, &config.color[CONF_ITITLE]);
756 else if (strcmp(var, "color_input_border") == 0)
757 parse_color(filename, lines, val, &config.color[CONF_IBORDER]);
758 else if (strcmp(var, "color_input_prompt") == 0)
759 parse_color(filename, lines, val, &config.color[CONF_IPROMPT]);
760 else if (strcmp(var, "color_menu") == 0)
761 parse_color(filename, lines, val, &config.color[CONF_MENU]);
762 else if (strcmp(var, "color_menu_selected") == 0)
763 parse_color(filename, lines, val, &config.color[CONF_MENUS]);
764 else if (strcmp(var, "color_menu_highlight") == 0)
765 parse_color(filename, lines, val, &config.color[CONF_MENUH]);
766 else if (strcmp(var, "color_menu_graphics") == 0)
767 parse_color(filename, lines, val,
768 &config.color[CONF_HISTORY_MENU_LG]);
769 else if (strcmp(var, "bind") == 0)
770 parse_key_binding(filename, lines, val);
771 else if (strcmp(var, "macro") == 0)
772 parse_macro(filename, lines, val);
773 else if (strcmp(var, "cbind") == 0) {
774 config.keys = Realloc(config.keys, (k + 2) *
775 sizeof(struct config_key_s *));
776 config.keys[k] = Calloc(1, sizeof(struct config_key_s));
777 p = val;
778 n = 0;
780 while (*p && !isspace(*p))
781 p++, n++;
783 c = *p;
784 *p = 0;
785 p -= n;
787 if (strcasecmp(p, "none") == 0)
788 config.keys[k]->type = KEY_DEFAULT;
789 else if (strcasecmp(p, "repeat") == 0)
790 config.keys[k]->type = KEY_REPEAT;
791 else if (strcasecmp(p, "set") == 0)
792 config.keys[k]->type = KEY_SET;
793 else
794 errx(EXIT_FAILURE, "%s(%i): invalid value \"%s\"", filename,
795 lines, p);
797 p = val + n;
798 *p = c;
800 while (*p && isspace(*p))
801 p++;
803 config.keys[k]->c = *p++;
805 while (isspace(*p))
806 p++;
808 config.keys[k++]->str = strdup(p);
809 config.keys[k] = NULL;
811 else
812 errx(EXIT_FAILURE, "%s(%i): invalid parameter \"%s\"", filename,
813 lines, var);
816 fclose(fp);
818 if (altengine) {
819 free(config.engine_cmd);
820 config.engine_cmd = NULL;
821 config.engine_cmd = altengine;