Update copyright year to 2015.
[cboard.git] / src / rcfile.c
blob2ad2b57fecb1e4b95b7832b25b5dad3dd527cffe
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2015 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_STRINGS_H
33 #include <strings.h>
34 #endif
36 #include "common.h"
37 #include "conf.h"
38 #include "misc.h"
39 #include "colors.h"
40 #include "keys.h"
41 #include "rcfile.h"
42 #include "common.h"
44 static int attributes(const char *filename, int line, char *str)
46 char *tmp;
47 int attrs = 0;
49 while ((tmp = strsep(&str, ",")) != NULL) {
50 if (strcasecmp(tmp, "BOLD") == 0)
51 attrs |= A_BOLD;
52 else if (strcasecmp(tmp, "REVERSE") == 0)
53 attrs |= A_REVERSE;
54 else if (strcasecmp(tmp, "NONE") == 0)
55 attrs |= A_NORMAL;
56 else if (strcasecmp(tmp, "DIM") == 0)
57 attrs |= A_DIM;
58 else if (strcasecmp(tmp, "STANDOUT") == 0)
59 attrs |= A_STANDOUT;
60 else if (strcasecmp(tmp, "UNDERLINE") == 0)
61 attrs |= A_UNDERLINE;
62 else if (strcasecmp(tmp, "BLINK") == 0)
63 attrs |= A_BLINK;
64 else if (strcasecmp(tmp, "INVISIBLE") == 0)
65 attrs |= A_INVIS;
66 else
67 errx(EXIT_FAILURE, _("%s(%i): invalid attribute \"%s\""), filename,
68 line, tmp);
71 return attrs;
74 static short color_name(const char *filename, int line, const char *color)
76 if (strcasecmp(color, "BLACK") == 0)
77 return COLOR_BLACK;
78 else if (strcasecmp(color, "WHITE") == 0)
79 return COLOR_WHITE;
80 else if (strcasecmp(color, "GREEN") == 0)
81 return COLOR_GREEN;
82 else if (strcasecmp(color, "YELLOW") == 0)
83 return COLOR_YELLOW;
84 else if (strcasecmp(color, "MAGENTA") == 0)
85 return COLOR_MAGENTA;
86 else if (strcasecmp(color, "BLUE") == 0)
87 return COLOR_BLUE;
88 else if (strcasecmp(color, "RED") == 0)
89 return COLOR_RED;
90 else if (strcasecmp(color, "CYAN") == 0)
91 return COLOR_CYAN;
92 else if (strcasecmp(color, "-") == 0)
94 else
95 errx(EXIT_FAILURE, _("%s(%i): invalid color \"%s\""), filename, line,
96 color);
98 return -1;
101 static void parse_color(const char *filename, int line, const char *str,
102 struct color_s *c)
104 char fg[16], bg[16], attr[64], nattr[64];
105 int n;
107 if ((n = sscanf(str, "%[a-zA-Z-] %[a-zA-Z-] %[a-zA-Z,-] %[a-zA-Z,-]", fg, bg,
108 attr, nattr)) < 2)
109 errx(EXIT_FAILURE, _ ("%s(%i): parse error"), filename, line);
111 if ((n = color_name(filename, line, fg)) >= 0)
112 c->fg = n;
114 if ((n = color_name(filename, line, bg)) >= 0)
115 c->bg = n;
117 c->attrs = c->nattrs = 0;
119 if (n > 2)
120 c->attrs = attributes(filename, line, attr);
122 if (n > 3)
123 c->nattrs = attributes(filename, line, nattr);
126 static int on_or_off(const char *filename, int lines, const char *str)
128 if (strcasecmp(str, "on") == 0 || strcasecmp(str, "1") == 0 ||
129 strcasecmp(str, "yes") == 0 || strcasecmp(str, "true") == 0)
130 return 1;
132 if (strcasecmp(str, "off") == 0 || strcasecmp(str, "0") == 0 ||
133 strcasecmp(str, "no") == 0 || strcasecmp(str, "false") == 0)
134 return 0;
136 errx(EXIT_FAILURE, _("%s(%i): invalid value \"%s\""), filename, lines, str);
139 void copydatafile(const char *dst, const char *src)
141 FILE *fp, *ofp;
142 char buf[LINE_MAX], *s;
144 snprintf(buf, sizeof(buf), "%s/%s", DATA_PATH, src);
146 if ((fp = fopen(buf, "r")) == NULL) {
147 if (errno != ENOENT)
148 warn("%s", buf);
149 return;
152 if ((ofp = fopen(dst, "w+")) == NULL) {
153 fclose(fp);
154 warn("%s", dst);
155 return;
158 while ((s = fgets(buf, sizeof(buf), fp)) != NULL)
159 fprintf(ofp, "%s", s);
161 fclose(fp);
162 fclose(ofp);
165 static char *fancy_key_name(wint_t c)
167 static char buf[64] = {0};
168 char *p;
170 strncpy(buf, keyname(c) ? keyname (c) : key_name (c), sizeof(buf)-1);
171 p = buf;
173 if (*p == '^' && *(p + 1) == '[')
174 return _("Escape");
176 if (*p == '^' && *(p + 1) == 'J')
177 return _ ("Enter");
179 if (strncasecmp(p, "KEY_", 4) == 0) {
180 for (p = buf; *p; p++)
181 *p = tolower(*p);
183 p = buf;
184 p += 4;
186 if (*p == 'f') {
187 char *t = buf + 4;
189 p += 2;
191 while (isdigit(*p))
192 *++t = *p++;
194 *++t = 0;
195 p = buf + 4;
197 else if (strcmp(p, "ppage") == 0)
198 return _("PgUp");
199 else if (strcmp(p, "npage") == 0)
200 return _ ("PgDown");
202 *p = toupper(*p);
203 return p;
206 if (*p == ' ')
207 return _("Space");
209 return p;
212 void add_key_binding(struct key_s ***dst, key_func *func, wint_t c,
213 char *desc, int repeat)
215 int i = 0;
216 struct key_s **k = *dst;
218 if (k)
219 for (i = 0; k[i]; i++);
221 k = Realloc(k, (i + 2) * sizeof(struct key_s *));
222 k[i] = Calloc(1, sizeof(struct key_s));
223 k[i]->f = func;
224 k[i]->c = c;
225 k[i]->r = repeat;
226 k[i]->key = str_to_wchar (fancy_key_name(c));
228 if (desc)
229 k[i]->d = str_to_wchar(desc);
231 i++;
232 k[i] = NULL;
233 *dst = k;
236 void set_default_keys()
238 add_key_binding(&history_keys, do_history_jump_next, KEY_UP, _("history jump next"), 1);
239 add_key_binding(&history_keys, do_history_jump_prev, KEY_DOWN, _("history jump previous"), 1);
240 add_key_binding(&history_keys, do_history_next, KEY_RIGHT, _("next move"), 1);
241 add_key_binding(&history_keys, do_history_prev, KEY_LEFT, _("previous move"), 1);
242 add_key_binding(&history_keys, do_history_half_move_toggle, ' ', _("toggle half move (ply) stepping"), 0);
243 add_key_binding(&history_keys, do_history_rotate_board, 'r', _("rotate board"), 0);
244 add_key_binding(&history_keys, do_history_jump, 'j', _("jump to move number"), 1);
245 add_key_binding(&history_keys, do_history_find_new, '/', _("new move text expression"), 0);
246 add_key_binding(&history_keys, do_history_find_next, ']', _("find next move text expression"), 1);
247 add_key_binding(&history_keys, do_history_find_prev, '[', _("find previous move text expression"), 1);
248 add_key_binding(&history_keys, do_history_annotate, CTRL_KEY('a'), _("annotate the previous move"), 0);
249 add_key_binding(&history_keys, do_history_rav_next, '+', _("next variation of the previous move"), 0);
250 add_key_binding(&history_keys, do_history_rav_prev, '-', _("previous variation of the previous move"), 0);
251 add_key_binding(&history_keys, do_history_menu, 'M', _("move history tree"), 0);
252 add_key_binding(&history_keys, do_history_help, KEY_F(1), _("more help"), 0);
253 add_key_binding(&history_keys, do_history_help, CTRL_KEY('g'), NULL, 0);
254 add_key_binding(&history_keys, do_history_toggle, 'h', _("exit history mode"), 0);
256 add_key_binding(&edit_keys, do_edit_select, ' ', _("select piece for movement"), 0);
257 add_key_binding(&edit_keys, do_edit_commit, '\n', _("commit selected piece"), 0);
258 add_key_binding(&edit_keys, do_edit_cancel_selected, KEY_ESCAPE, _("cancel selected piece"), 0);
259 add_key_binding(&edit_keys, do_edit_delete, 'd', _("remove the piece under the cursor"), 0);
260 add_key_binding(&edit_keys, do_edit_insert, 'i', _("insert piece"), 0);
261 add_key_binding(&edit_keys, do_edit_toggle_castle, 'c', _("toggle castling availability"), 0);
262 add_key_binding(&edit_keys, do_edit_enpassant, 'p', _("toggle enpassant square"), 0);
263 add_key_binding(&edit_keys, do_edit_switch_turn, 'w', _("toggle turn"), 0);
264 add_key_binding(&edit_keys, do_edit_help, KEY_F(1), _("more help"), 0);
265 add_key_binding(&edit_keys, do_edit_help, CTRL_KEY('g'), NULL, 0);
266 add_key_binding(&edit_keys, do_edit_exit, 'e', _("exit edit mode"), 0);
268 add_key_binding(&play_keys, do_play_select, ' ', _("select piece for movement"), 0);
269 add_key_binding(&play_keys, do_play_commit, '\n', _("commit selected piece"), 0);
270 add_key_binding(&play_keys, do_play_cancel_selected, KEY_ESCAPE, _("cancel selected piece"), 0);
271 add_key_binding(&play_keys, do_play_set_clock, 'C', _("set clock"), 0);
272 // add_key_binding(&play_keys, do_play_switch_turn, 'w', _("switch turn"), 0);
273 add_key_binding(&play_keys, do_play_undo, 'u', _("undo previous move"), 1);
274 add_key_binding(&play_keys, do_play_go, 'g', _("force the chess engine to make the next move"), 0);
275 add_key_binding(&play_keys, do_play_send_command, '|', _("send a command to the chess engine"), 0);
276 add_key_binding(&play_keys, do_play_toggle_eh_mode, 'w', _("toggle engine/human play"), 0);
277 add_key_binding(&play_keys, do_play_toggle_engine, 'E', _("toggle engine/engine play"), 0);
278 add_key_binding(&play_keys, do_play_toggle_human, 'H', _("toggle human/human play"), 0);
279 add_key_binding(&play_keys, do_play_toggle_pause, 'p', _("toggle pausing of this game"), 0);
280 add_key_binding(&play_keys, do_play_history_mode, 'h', _("enter history mode"), 0);
281 add_key_binding(&play_keys, do_play_edit_mode, 'e', _("enter edit mode"), 0);
282 add_key_binding(&play_keys, do_play_help, KEY_F(1), _("more help"), 0);
283 add_key_binding(&play_keys, do_play_help, CTRL_KEY('g'), NULL, 0);
285 add_key_binding(&global_keys, do_global_tag_edit, CTRL_KEY('t'), _("edit roster tags"), 0);
286 add_key_binding(&global_keys, do_global_tag_view, 't', _("view roster tags"), 0);
287 add_key_binding(&global_keys, do_global_find_new, '?', _("new find game expression"), 0);
288 add_key_binding(&global_keys, do_global_find_next, '}', _("find next game"), 1);
289 add_key_binding(&global_keys, do_global_find_prev, '{', _("find previous game"), 1);
290 add_key_binding(&global_keys, do_global_new_game, CTRL_KEY('n'), _("new game or round"), 0);
291 add_key_binding(&global_keys, do_global_new_all, CTRL_KEY('k'), _("new game from scratch"), 0);
292 add_key_binding(&global_keys, do_global_copy_game, CTRL_KEY('i'), _("copy current game"), 0);
293 add_key_binding(&global_keys, do_global_next_game, '>', _("next game"), 1);
294 add_key_binding(&global_keys, do_global_prev_game, '<', _("previous game"), 1);
295 add_key_binding(&global_keys, do_global_game_jump, 'J', _("jump to game"), 1);
296 add_key_binding(&global_keys, do_global_toggle_delete, 'X', _("toggle delete flag"), 1);
297 add_key_binding(&global_keys, do_global_delete_game, CTRL_KEY('X'), _("delete the current or flagged games"), 0);
298 add_key_binding(&global_keys, do_global_resume_game, CTRL_KEY('r'), _("load a PGN file"), 0);
299 add_key_binding(&global_keys, do_global_save_game, 's', _("save game"), 0);
300 add_key_binding(&global_keys, do_global_toggle_board_details, CTRL_KEY('d'), _("toggle board details"), 0);
301 add_key_binding(&global_keys, do_global_toggle_strict_castling, CTRL_KEY('p'), _("toggle strict castling"), 0);
302 add_key_binding(&global_keys, do_global_toggle_engine_window, 'W', _("toggle chess engine IO window"), 0);
303 #ifdef WITH_LIBPERL
304 add_key_binding(&global_keys, do_global_perl, CTRL_KEY('O'), _("Call PERL subroutine"), 0);
305 #endif
306 add_key_binding(&global_keys, do_global_about, KEY_F(10), _("version information"), 0);
307 add_key_binding(&global_keys, do_global_redraw, CTRL_KEY('L'), _("redraw the screen"), 0);
308 add_key_binding(&global_keys, NULL, KEY_F(1), _("more help"), 0);
309 add_key_binding(&global_keys, NULL, CTRL_KEY('g'), NULL, 0);
310 add_key_binding(&global_keys, do_global_quit, 'Q', _("quit"), 0);
313 void set_config_defaults()
315 struct stat st;
317 config.pattern = strdup("*.[Pp][Gg][Nn]*");
318 config.engine_cmd = strdup("gnuchess --xboard");
319 config.engine_protocol = 1;
320 config.jumpcount = 5;
321 config.linegraphics = 1;
322 config.saveprompt = 1;
323 config.deleteprompt = 1;
324 config.validmoves = 1;
325 config.details = 1;
326 config.showattacks = 1;
327 config.coordsyleft = TRUE;
328 config.fmpolyglot = FALSE;
329 config.boardleft = TRUE;
330 config.exitdialogbox = TRUE;
331 config.enginecmdblacktag = TRUE;
332 config.bprevmove = TRUE;
333 config.utf8_pieces = 1;
335 set_default_colors();
337 if (stat(config.nagfile, &st) == -1) {
338 if (errno == ENOENT)
339 copydatafile(config.nagfile, "nag.data");
340 else
341 warn("%s", config.nagfile);
344 if (stat(config.ccfile, &st) == -1) {
345 if (errno == ENOENT)
346 copydatafile(config.ccfile, "cc.data");
347 else
348 warn("%s", config.ccfile);
352 static void update_key(struct key_s **dst, struct custom_key_s config_key,
353 wint_t c, char *desc)
355 int i;
357 for (i = 0; dst[i]; i++) {
358 if (dst[i]->f == config_key.func) {
359 dst[i]->c = c;
361 if (dst[i]->key)
362 free(dst[i]->key);
364 dst[i]->key = str_to_wchar(fancy_key_name(c));
365 if (desc) {
366 free(dst[i]->d);
367 dst[i]->d = str_to_wchar(desc);
370 goto done;
374 add_key_binding(&dst, config_key.func, c,
375 (desc) ? desc : _("no description"), config_key.r);
377 done:
378 return;
381 static struct known_key_s
383 wint_t c;
384 char *name;
385 } known_keys[] = {
386 { KEY_UP, "up" },
387 { KEY_DOWN, "down" },
388 { KEY_LEFT, "left" },
389 { KEY_RIGHT, "right" },
390 { KEY_HOME, "home" },
391 { KEY_END, "end" },
392 { KEY_DC, "delete" },
393 { KEY_PPAGE, "pgup" },
394 { KEY_NPAGE, "pgdn" },
395 { KEY_IC, "insert" },
396 { ' ', "space" },
397 { KEY_ESCAPE, "escape" },
398 { '\n', "enter" },
399 { 0, NULL }
402 static wint_t parse_key(const char *filename, int lines, wchar_t **key)
404 wchar_t *p = key ? *key : NULL;
405 wchar_t *orig = key ? *key : NULL;
406 wint_t c = 0;
408 if (!key || !wcslen (*key))
409 return 0;
411 if (*p == '\"') {
412 if (orig[wcslen(orig) - 1] != '\"')
413 errx(EXIT_FAILURE, _("%s(%i): unbalanced quotes"), filename, lines);
415 p++;
416 orig[wcslen(orig) - 1] = 0;
419 if (*p == '<') {
420 int i;
422 p++;
424 for (i = 0; known_keys[i].name; i++) {
425 wchar_t *wc = str_to_wchar (known_keys[i].name);
427 if (!wcsncasecmp (p, wc, wcslen (wc))) {
428 c = known_keys[i].c;
429 p += strlen (known_keys[i].name);
430 free (wc);
431 break;
434 free (wc);
437 if (!c) {
438 if (*p == '^') {
439 p++;
440 c = CTRL_KEY(*p++);
442 else if (*p == 'F' || *p == 'f') {
443 char *str = wchar_to_str (++p);
445 c = KEY_F(atoi(str));
446 p += integer_len(atoi(str));
447 free (str);
451 if (!c)
452 c = *p++;
454 if (*p++ != '>')
455 errx(EXIT_FAILURE, _("%s(%i): parse error \"%ls\""), filename,
456 lines, orig);
458 else if (*p == '\\') {
459 p++;
460 c = *p++;
462 else
463 c = *p++;
465 orig += wcslen(orig) - wcslen(p);
466 *key = orig;
467 return c;
470 static void parse_key_binding(const char *filename, int lines, char *val)
472 char mode[64], func[64];
473 wchar_t desc[64] = {0};
474 wchar_t key[64];
475 int n;
476 int m = 0;
477 wint_t c = 0;
478 int f;
479 int i;
480 wchar_t *p;
481 char *str;
483 n = sscanf(val, "%s %ls %s %63lc", mode, key, func, desc);
485 if (n < 3)
486 errx(EXIT_FAILURE, _ ("%s(%i): too few arguments"), filename, lines);
488 if (strcasecmp(mode, "history") == 0)
489 m = MODE_HISTORY;
490 else if (strcasecmp(mode, "play") == 0)
491 m = MODE_PLAY;
492 else if (strcasecmp(mode, "edit") == 0)
493 m = MODE_EDIT;
494 else
495 errx(EXIT_FAILURE, _ ("%s(%i): invalid game mode \"%s\""), filename,
496 lines, mode);
498 p = key;
499 c = parse_key(filename, lines, &p);
501 if (m != -1) {
502 for (i = 0; global_keys[i]; i++) {
503 if (global_keys[i]->c == c)
504 errx(EXIT_FAILURE,
505 _("%s(%i): key \"%ls\" conflicts with a global key"),
506 filename, lines, key);
510 for (f = -2, i = 0; config_keys[i].name; i++) {
511 if (strcmp(config_keys[i].name, func) == 0 &&
512 config_keys[i].mode == m) {
513 f = i;
514 break;
518 if (f == -2)
519 errx(EXIT_FAILURE, _("%s(%i): invalid command \"%s\""), filename,
520 lines, func);
522 str = wchar_to_str (desc);
524 switch (m) {
525 case MODE_PLAY:
526 update_key(play_keys, config_keys[f], c, (n > 3) ? str : NULL);
527 break;
528 case MODE_HISTORY:
529 update_key(history_keys, config_keys[f], c, (n > 3) ? str : NULL);
530 break;
531 case MODE_EDIT:
532 update_key(edit_keys, config_keys[f], c, (n > 3) ? str : NULL);
533 break;
534 default:
535 update_key(global_keys, config_keys[f], c, (n > 3) ? str : NULL);
536 break;
539 free (str);
542 static void parse_macro(const char *filename, int lines, char *val)
544 char mode[16];
545 wchar_t keys[2048] = {0}, key[8];
546 int n;
547 int m;
548 wint_t c;
549 int i = 0;
550 wchar_t *p;
552 n = sscanf(val, "%s %ls %2047lc", 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,
567 lines, 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(wint_t));
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] = {0}, val[LINE_MAX - sizeof(var) - 1] = {0};
606 char token[MAX_PGN_LINE_LEN + 1] = {0};
607 char value[MAX_PGN_LINE_LEN + 1] = {0};
608 char *p;
610 lines++;
611 line = trim(line);
613 if (!line[0] || line[0] == '#')
614 continue;
616 if ((n = sscanf(line, "%s %[^\n]", var, val)) != 2)
617 errx(EXIT_FAILURE, _("%s(%i): parse error %i"), filename, lines,n);
619 p = strdup(trim(val));
620 strncpy(val, p, sizeof(val)-1);
621 free(p);
622 p = strdup(trim(var));
623 strncpy(var, p, sizeof(var)-1);
624 free(p);
626 if (strcmp(var, "jump_count") == 0) {
627 if (!isinteger(val))
628 errx(EXIT_FAILURE, _("%s(%i): value is not an integer"), filename,
629 lines);
631 config.jumpcount = atoi(val);
633 else if (strcmp(var, "engine_init") == 0) {
634 config.einit = Realloc(config.einit, (init + 2) * sizeof(wchar_t *));
635 config.einit[init++] = str_to_wchar (val);
636 config.einit[init] = NULL;
638 else if (strcmp(var, "pattern") == 0) {
639 free(config.pattern);
640 config.pattern = strdup(val);
642 else if (strcmp(var, "mpl") == 0) {
643 if (!isinteger(val))
644 errx(EXIT_FAILURE, _("%s(%i): value is not an integer"),
645 filename, lines);
646 pgn_config_set(PGN_MPL, atoi(val));
648 else if (strcmp(var, "stop_on_error") == 0)
649 pgn_config_set(PGN_STOP_ON_ERROR, on_or_off(filename, lines, val));
650 else if (strcmp(var, "tag") == 0) {
651 if ((n = sscanf(val, "%s %s ", token, value)) < 1 || 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)-1);
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, "show_attacks") == 0)
685 config.showattacks = on_or_off(filename, lines, val);
686 else if (strcmp(var, "coords_y_left") == 0 )
687 config.coordsyleft = on_or_off(filename, lines, val);
688 else if (strcmp(var, "fm_polyglot") == 0 )
689 config.fmpolyglot = on_or_off(filename, lines, val);
690 else if (strcmp(var, "board_left") == 0 )
691 config.boardleft = on_or_off(filename, lines, val);
692 else if (strcmp(var, "exit_dialog_box") == 0 )
693 config.exitdialogbox = on_or_off(filename, lines, val);
694 else if (strcmp(var, "engine_cmd_blacktag") == 0 )
695 config.enginecmdblacktag = on_or_off(filename, lines, val);
696 else if (strcmp(var, "board_prev_move") == 0 )
697 config.bprevmove = on_or_off(filename, lines, val);
698 else if (strcmp(var, "strict_castling") == 0)
699 pgn_config_set(PGN_STRICT_CASTLING, on_or_off(filename, lines, val));
700 else if (strcmp(var, "engine_cmd") == 0)
701 altengine = strdup(val);
702 else if (strcmp(var, "engine_protocol") == 0) {
703 if (!isinteger(val))
704 errx(EXIT_FAILURE, _ ("%s(%i): value is not an integer"),
705 filename, lines);
707 config.engine_protocol = atoi(val);
709 if (config.engine_protocol != 1 && config.engine_protocol != 2)
710 errx(EXIT_FAILURE, _ ("%s(%i): invalid value"), filename, lines);
712 else if (strcmp(var, "utf8_pieces") == 0)
713 config.utf8_pieces = on_or_off (filename, lines, val);
714 else if (strcmp(var, "color_board_window") == 0)
715 parse_color(filename, lines, val, &config.color[CONF_BDWINDOW]);
716 else if (strcmp(var, "color_board_selected") == 0)
717 parse_color(filename, lines, val, &config.color[CONF_BSELECTED]);
718 else if (strcmp(var, "color_board_white_moves") == 0)
719 parse_color(filename, lines, val, &config.color[CONF_BMOVESW]);
720 else if (strcmp(var, "color_board_black_moves") == 0)
721 parse_color(filename, lines, val, &config.color[CONF_BMOVESB]);
722 else if (strcmp(var, "color_board_count") == 0)
723 parse_color(filename, lines, val, &config.color[CONF_BCOUNT]);
724 else if (strcmp(var, "color_board_cursor") == 0)
725 parse_color(filename, lines, val, &config.color[CONF_BCURSOR]);
726 else if (strcmp(var, "color_board_black") == 0)
727 parse_color(filename, lines, val, &config.color[CONF_BBLACK]);
728 else if (strcmp(var, "color_board_white") == 0)
729 parse_color(filename, lines, val, &config.color[CONF_BWHITE]);
730 else if (strcmp(var, "color_board_graphics") == 0)
731 parse_color(filename, lines, val, &config.color[CONF_BGRAPHICS]);
732 else if (strcmp(var, "color_board_coords") == 0)
733 parse_color(filename, lines, val, &config.color[CONF_BCOORDS]);
734 else if (strcmp(var, "color_board_castling") == 0)
735 parse_color(filename, lines, val, &config.color[CONF_BCASTLING]);
736 else if (strcmp(var, "color_board_enpassant") == 0)
737 parse_color(filename, lines, val, &config.color[CONF_BENPASSANT]);
738 else if (strcmp(var, "color_board_attack") == 0)
739 parse_color(filename, lines, val, &config.color[CONF_BATTACK]);
740 else if (strcmp(var, "color_board_prev_move") == 0)
741 parse_color(filename, lines, val, &config.color[CONF_BPREVMOVE]);
742 else if (strcmp(var, "color_status_window") == 0)
743 parse_color(filename, lines, val, &config.color[CONF_SWINDOW]);
744 else if (strcmp(var, "color_status_title") == 0)
745 parse_color(filename, lines, val, &config.color[CONF_STITLE]);
746 else if (strcmp(var, "color_status_border") == 0)
747 parse_color(filename, lines, val, &config.color[CONF_SBORDER]);
748 else if (strcmp(var, "color_status_notify") == 0)
749 parse_color(filename, lines, val, &config.color[CONF_SNOTIFY]);
750 else if (strcmp(var, "color_status_engine") == 0)
751 parse_color(filename, lines, val, &config.color[CONF_SENGINE]);
752 else if (strcmp(var, "color_tag_window") == 0)
753 parse_color(filename, lines, val, &config.color[CONF_TWINDOW]);
754 else if (strcmp(var, "color_tag_title") == 0)
755 parse_color(filename, lines, val, &config.color[CONF_TTITLE]);
756 else if (strcmp(var, "color_tag_border") == 0)
757 parse_color(filename, lines, val, &config.color[CONF_TBORDER]);
758 else if (strcmp(var, "color_history_window") == 0)
759 parse_color(filename, lines, val, &config.color[CONF_HWINDOW]);
760 else if (strcmp(var, "color_history_title") == 0)
761 parse_color(filename, lines, val, &config.color[CONF_HTITLE]);
762 else if (strcmp(var, "color_history_border") == 0)
763 parse_color(filename, lines, val, &config.color[CONF_HBORDER]);
764 else if (strcmp(var, "color_message_window") == 0)
765 parse_color(filename, lines, val, &config.color[CONF_MWINDOW]);
766 else if (strcmp(var, "color_message_title") == 0)
767 parse_color(filename, lines, val, &config.color[CONF_MTITLE]);
768 else if (strcmp(var, "color_message_border") == 0)
769 parse_color(filename, lines, val, &config.color[CONF_MBORDER]);
770 else if (strcmp(var, "color_message_prompt") == 0)
771 parse_color(filename, lines, val, &config.color[CONF_MPROMPT]);
772 else if (strcmp(var, "color_input_window") == 0)
773 parse_color(filename, lines, val, &config.color[CONF_IWINDOW]);
774 else if (strcmp(var, "color_input_title") == 0)
775 parse_color(filename, lines, val, &config.color[CONF_ITITLE]);
776 else if (strcmp(var, "color_input_border") == 0)
777 parse_color(filename, lines, val, &config.color[CONF_IBORDER]);
778 else if (strcmp(var, "color_input_prompt") == 0)
779 parse_color(filename, lines, val, &config.color[CONF_IPROMPT]);
780 else if (strcmp(var, "color_menu") == 0)
781 parse_color(filename, lines, val, &config.color[CONF_MENU]);
782 else if (strcmp(var, "color_menu_selected") == 0)
783 parse_color(filename, lines, val, &config.color[CONF_MENUS]);
784 else if (strcmp(var, "color_menu_highlight") == 0)
785 parse_color(filename, lines, val, &config.color[CONF_MENUH]);
786 else if (strcmp(var, "color_menu_graphics") == 0)
787 parse_color(filename, lines, val,
788 &config.color[CONF_HISTORY_MENU_LG]);
789 else if (strcmp(var, "bind") == 0)
790 parse_key_binding(filename, lines, val);
791 else if (strcmp(var, "macro") == 0)
792 parse_macro(filename, lines, val);
793 else if (strcmp(var, "cbind") == 0) {
794 config.keys = Realloc(config.keys, (k + 2) *
795 sizeof(struct config_key_s *));
796 config.keys[k] = Calloc(1, sizeof(struct config_key_s));
797 p = val;
798 n = 0;
800 while (*p && !isspace(*p))
801 p++, n++;
803 c = *p;
804 *p = 0;
805 p -= n;
807 if (strcasecmp(p, "none") == 0)
808 config.keys[k]->type = KEY_DEFAULT;
809 else if (strcasecmp(p, "repeat") == 0)
810 config.keys[k]->type = KEY_REPEAT;
811 else if (strcasecmp(p, "set") == 0)
812 config.keys[k]->type = KEY_SET;
813 else
814 errx(EXIT_FAILURE, _ ("%s(%i): invalid value \"%s\""), filename,
815 lines, p);
817 p = val + n;
818 *p = c;
820 while (*p && isspace(*p))
821 p++;
823 config.keys[k]->c = *p++;
825 while (isspace(*p))
826 p++;
828 config.keys[k++]->str = str_to_wchar (p);
829 config.keys[k] = NULL;
831 else
832 errx(EXIT_FAILURE, _ ("%s(%i): invalid parameter \"%s\""), filename,
833 lines, var);
836 fclose(fp);
838 if (altengine) {
839 free(config.engine_cmd);
840 config.engine_cmd = NULL;
841 config.engine_cmd = altengine;
844 if (config.enginecmdblacktag)
845 pgn_tag_add(&config.tag, "Black", config.engine_cmd);