Add copy_game_fen.
[cboard.git] / src / rcfile.c
blob34d73cfbca2814c5e10dbc10d9c580d1d008dfe3
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2018 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
45 attributes (const char *filename, int line, char *str)
47 char *tmp;
48 int attrs = 0;
50 while ((tmp = strsep (&str, ",")) != NULL)
52 if (strcasecmp (tmp, "BOLD") == 0)
53 attrs |= A_BOLD;
54 else if (strcasecmp (tmp, "REVERSE") == 0)
55 attrs |= A_REVERSE;
56 else if (strcasecmp (tmp, "NONE") == 0)
57 attrs |= A_NORMAL;
58 else if (strcasecmp (tmp, "DIM") == 0)
59 attrs |= A_DIM;
60 else if (strcasecmp (tmp, "STANDOUT") == 0)
61 attrs |= A_STANDOUT;
62 else if (strcasecmp (tmp, "UNDERLINE") == 0)
63 attrs |= A_UNDERLINE;
64 else if (strcasecmp (tmp, "BLINK") == 0)
65 attrs |= A_BLINK;
66 else if (strcasecmp (tmp, "INVISIBLE") == 0)
67 attrs |= A_INVIS;
68 else
69 errx (EXIT_FAILURE, _("%s(%i): invalid attribute \"%s\""), filename,
70 line, tmp);
73 return attrs;
76 static short
77 color_name (const char *filename, int line, const char *color)
79 if (strcasecmp (color, "BLACK") == 0)
80 return COLOR_BLACK;
81 else if (strcasecmp (color, "WHITE") == 0)
82 return COLOR_WHITE;
83 else if (strcasecmp (color, "GREEN") == 0)
84 return COLOR_GREEN;
85 else if (strcasecmp (color, "YELLOW") == 0)
86 return COLOR_YELLOW;
87 else if (strcasecmp (color, "MAGENTA") == 0)
88 return COLOR_MAGENTA;
89 else if (strcasecmp (color, "BLUE") == 0)
90 return COLOR_BLUE;
91 else if (strcasecmp (color, "RED") == 0)
92 return COLOR_RED;
93 else if (strcasecmp (color, "CYAN") == 0)
94 return COLOR_CYAN;
95 else if (strcasecmp (color, "-") == 0)
97 else
98 errx (EXIT_FAILURE, _("%s(%i): invalid color \"%s\""), filename, line,
99 color);
101 return -1;
104 static void
105 parse_color (const char *filename, int line, const char *str,
106 struct color_s *c)
108 char fg[16], bg[16], attr[64], nattr[64];
109 int n;
111 if ((n =
112 sscanf (str, "%[a-zA-Z-] %[a-zA-Z-] %[a-zA-Z,-] %[a-zA-Z,-]", fg, bg,
113 attr, nattr)) < 2)
114 errx (EXIT_FAILURE, _("%s(%i): parse error"), filename, line);
116 if ((n = color_name (filename, line, fg)) >= 0)
117 c->fg = n;
119 if ((n = color_name (filename, line, bg)) >= 0)
120 c->bg = n;
122 c->attrs = c->nattrs = 0;
124 if (n > 2)
125 c->attrs = attributes (filename, line, attr);
127 if (n > 3)
128 c->nattrs = attributes (filename, line, nattr);
131 static int
132 on_or_off (const char *filename, int lines, const char *str)
134 if (strcasecmp (str, "on") == 0 || strcasecmp (str, "1") == 0 ||
135 strcasecmp (str, "yes") == 0 || strcasecmp (str, "true") == 0)
136 return 1;
138 if (strcasecmp (str, "off") == 0 || strcasecmp (str, "0") == 0 ||
139 strcasecmp (str, "no") == 0 || strcasecmp (str, "false") == 0)
140 return 0;
142 errx (EXIT_FAILURE, _("%s(%i): invalid value \"%s\""), filename, lines,
143 str);
146 void
147 copydatafile (const char *dst, const char *src)
149 FILE *fp, *ofp;
150 char buf[LINE_MAX], *s;
152 snprintf (buf, sizeof (buf), "%s/%s", DATA_PATH, src);
154 if ((fp = fopen (buf, "r")) == NULL)
156 if (errno != ENOENT)
157 warn ("%s", buf);
158 return;
161 if ((ofp = fopen (dst, "w+")) == NULL)
163 fclose (fp);
164 warn ("%s", dst);
165 return;
168 while ((s = fgets (buf, sizeof (buf), fp)) != NULL)
169 fprintf (ofp, "%s", s);
171 fclose (fp);
172 fclose (ofp);
175 char *
176 fancy_key_name (wint_t c)
178 static char buf[64] = { 0 };
179 char *p;
181 strncpy (buf, keyname (c) ? keyname (c) : key_name (c), sizeof (buf) - 1);
182 p = buf;
184 if (*p == '^' && *(p + 1) == '[')
185 return _("Escape");
187 if (*p == '^' && *(p + 1) == 'J')
188 return _("Enter");
190 if (strncasecmp (p, "KEY_", 4) == 0)
192 for (p = buf; *p; p++)
193 *p = tolower (*p);
195 p = buf;
196 p += 4;
198 if (*p == 'f')
200 char *t = buf + 4;
202 p += 2;
204 while (isdigit (*p))
205 *++t = *p++;
207 *++t = 0;
208 p = buf + 4;
210 else if (strcmp (p, "ppage") == 0)
211 return _("PgUp");
212 else if (strcmp (p, "npage") == 0)
213 return _("PgDown");
215 *p = toupper (*p);
216 return p;
219 if (*p == ' ')
220 return _("Space");
222 return p;
225 void
226 add_key_binding (struct key_s ***dst, key_func * func, wint_t c,
227 char *desc, int repeat)
229 int i = 0;
230 struct key_s **k = *dst;
232 if (k)
233 for (i = 0; k[i]; i++);
235 k = Realloc (k, (i + 2) * sizeof (struct key_s *));
236 k[i] = Calloc (1, sizeof (struct key_s));
237 k[i]->f = func;
238 k[i]->c = c;
239 k[i]->r = repeat;
240 k[i]->key = str_to_wchar (fancy_key_name (c));
242 if (desc)
243 k[i]->d = str_to_wchar (desc);
245 i++;
246 k[i] = NULL;
247 *dst = k;
250 void
251 set_default_keys ()
253 add_key_binding (&history_keys, do_history_jump_next, KEY_UP,
254 _("history jump next"), 1);
255 add_key_binding (&history_keys, do_history_jump_prev, KEY_DOWN,
256 _("history jump previous"), 1);
257 add_key_binding (&history_keys, do_history_next, KEY_RIGHT, _("next move"),
259 add_key_binding (&history_keys, do_history_prev, KEY_LEFT,
260 _("previous move"), 1);
261 add_key_binding (&history_keys, do_history_half_move_toggle, ' ',
262 _("toggle half move (ply) stepping"), 0);
263 add_key_binding (&history_keys, do_history_rotate_board, 'r',
264 _("rotate board"), 0);
265 add_key_binding (&history_keys, do_history_jump, 'j',
266 _("jump to move number"), 1);
267 add_key_binding (&history_keys, do_history_find_new, '/',
268 _("new move text expression"), 0);
269 add_key_binding (&history_keys, do_history_find_next, ']',
270 _("find next move text expression"), 1);
271 add_key_binding (&history_keys, do_history_find_prev, '[',
272 _("find previous move text expression"), 1);
273 add_key_binding (&history_keys, do_history_annotate, CTRL_KEY ('a'),
274 _("annotate the previous move"), 0);
275 add_key_binding (&history_keys, do_history_rav_next, '+',
276 _("next variation of the previous move"), 0);
277 add_key_binding (&history_keys, do_history_rav_prev, '-',
278 _("previous variation of the previous move"), 0);
279 add_key_binding (&history_keys, do_history_menu, 'M',
280 _("move history tree"), 0);
281 add_key_binding (&history_keys, do_history_toggle, 'h',
282 _("exit history mode"), 0);
284 add_key_binding (&edit_keys, do_edit_select, ' ',
285 _("select piece for movement"), 0);
286 add_key_binding (&edit_keys, do_edit_commit, '\n',
287 _("commit selected piece"), 0);
288 add_key_binding (&edit_keys, do_edit_cancel_selected, KEY_ESCAPE,
289 _("cancel selected piece"), 0);
290 add_key_binding (&edit_keys, do_edit_delete, 'd',
291 _("remove the piece under the cursor"), 0);
292 add_key_binding (&edit_keys, do_edit_insert, 'i', _("insert piece"), 0);
293 add_key_binding (&edit_keys, do_edit_toggle_castle, 'c',
294 _("toggle castling availability"), 0);
295 add_key_binding (&edit_keys, do_edit_enpassant, 'p',
296 _("toggle enpassant square"), 0);
297 add_key_binding (&edit_keys, do_edit_switch_turn, 'w', _("toggle turn"), 0);
298 add_key_binding (&edit_keys, do_edit_exit, 'e', _("exit edit mode"), 0);
300 add_key_binding (&play_keys, do_play_select, ' ',
301 _("select piece for movement"), 0);
302 add_key_binding (&play_keys, do_play_commit, '\n',
303 _("commit selected piece"), 0);
304 add_key_binding (&play_keys, do_play_cancel_selected, KEY_ESCAPE,
305 _("cancel selected piece"), 0);
306 add_key_binding (&play_keys, do_play_set_clock, 'C', _("set clock"), 0);
307 // add_key_binding(&play_keys, do_play_switch_turn, 'w', _("switch turn"), 0);
308 add_key_binding (&play_keys, do_play_undo, 'u', _("undo previous move"), 1);
309 add_key_binding (&play_keys, do_play_go, 'g',
310 _("force the chess engine to make the next move"), 0);
311 add_key_binding (&play_keys, do_play_send_command, '|',
312 _("send a command to the chess engine"), 0);
313 add_key_binding (&play_keys, do_play_toggle_eh_mode, 'w',
314 _("toggle engine/human play"), 0);
315 add_key_binding (&play_keys, do_play_toggle_engine, 'E',
316 _("toggle engine/engine play"), 0);
317 add_key_binding (&play_keys, do_play_toggle_human, 'H',
318 _("toggle human/human play"), 0);
319 add_key_binding (&play_keys, do_play_toggle_pause, 'p',
320 _("toggle pausing of this game"), 0);
321 add_key_binding (&play_keys, do_play_history_mode, 'h',
322 _("enter history mode"), 0);
323 add_key_binding (&play_keys, do_play_edit_mode, 'e', _("enter edit mode"),
325 add_key_binding (&play_keys, do_play_toggle_strict_castling,
326 CTRL_KEY ('p'), _("toggle strict castling"), 0);
328 add_key_binding (&global_keys, do_global_tag_edit, CTRL_KEY ('t'),
329 _("edit roster tags"), 0);
330 add_key_binding (&global_keys, do_global_tag_view, 't',
331 _("view roster tags"), 0);
332 add_key_binding (&global_keys, do_global_find_new, '?',
333 _("new find game expression"), 0);
334 add_key_binding (&global_keys, do_global_find_next, '}',
335 _("find next game"), 1);
336 add_key_binding (&global_keys, do_global_find_prev, '{',
337 _("find previous game"), 1);
338 add_key_binding (&global_keys, do_global_new_game, CTRL_KEY ('n'),
339 _("new game or round"), 0);
340 add_key_binding (&global_keys, do_global_new_all, CTRL_KEY ('k'),
341 _("new game from scratch"), 0);
342 add_key_binding (&global_keys, do_global_copy_game, CTRL_KEY ('i'),
343 _("copy current game"), 0);
344 add_key_binding (&global_keys, do_global_copy_game_fen, CTRL_KEY ('f'),
345 _("copy current game as FEN tag"), 0);
346 add_key_binding (&global_keys, do_global_next_game, '>', _("next game"), 1);
347 add_key_binding (&global_keys, do_global_prev_game, '<', _("previous game"),
349 add_key_binding (&global_keys, do_global_game_jump, 'J', _("jump to game"),
351 add_key_binding (&global_keys, do_global_toggle_delete, 'X',
352 _("toggle delete flag"), 1);
353 add_key_binding (&global_keys, do_global_delete_game, CTRL_KEY ('X'),
354 _("delete the current or flagged games"), 0);
355 add_key_binding (&global_keys, do_global_resume_game, CTRL_KEY ('r'),
356 _("load a PGN file"), 0);
357 add_key_binding (&global_keys, do_global_save_game, 's', _("save game"), 0);
358 add_key_binding (&global_keys, do_global_toggle_board_details,
359 CTRL_KEY ('d'), _("toggle board details"), 0);
360 add_key_binding (&global_keys, do_global_toggle_engine_window, 'W',
361 _("toggle chess engine IO window"), 0);
362 #ifdef WITH_LIBPERL
363 add_key_binding (&global_keys, do_global_perl, CTRL_KEY ('O'),
364 _("Call PERL subroutine"), 0);
365 #endif
366 add_key_binding (&global_keys, do_global_about, KEY_F (10),
367 _("version information"), 0);
368 add_key_binding (&global_keys, do_global_redraw, CTRL_KEY ('L'),
369 _("redraw the screen"), 0);
370 add_key_binding (&global_keys, do_global_help, KEY_F (1), NULL, 0);
371 add_key_binding (&global_keys, do_global_quit, 'Q', _("quit"), 0);
374 void
375 set_config_defaults ()
377 struct stat st;
379 config.pattern = strdup ("*.[Pp][Gg][Nn]*");
380 config.engine_cmd = strdup ("gnuchess --xboard");
381 config.engine_protocol = 1;
382 config.jumpcount = 5;
383 config.linegraphics = 1;
384 config.saveprompt = 1;
385 config.deleteprompt = 1;
386 config.validmoves = 1;
387 config.details = 1;
388 config.showattacks = 1;
389 config.coordsyleft = TRUE;
390 config.fmpolyglot = FALSE;
391 config.boardleft = TRUE;
392 config.exitdialogbox = TRUE;
393 config.enginecmdblacktag = TRUE;
394 config.bprevmove = TRUE;
395 config.utf8_pieces = 1;
396 config.engine_timeout = 10;
398 set_default_colors ();
400 if (stat (config.nagfile, &st) == -1)
402 if (errno == ENOENT)
403 copydatafile (config.nagfile, "nag.data");
404 else
405 warn ("%s", config.nagfile);
408 if (stat (config.ccfile, &st) == -1)
410 if (errno == ENOENT)
411 copydatafile (config.ccfile, "cc.data");
412 else
413 warn ("%s", config.ccfile);
417 static void
418 update_key (struct key_s **dst, struct custom_key_s config_key,
419 wint_t c, char *desc)
421 int i;
423 for (i = 0; dst[i]; i++)
425 if (dst[i]->f == config_key.func)
427 dst[i]->c = c;
429 if (dst[i]->key)
430 free (dst[i]->key);
432 dst[i]->key = str_to_wchar (fancy_key_name (c));
433 if (desc)
435 free (dst[i]->d);
436 dst[i]->d = str_to_wchar (desc);
439 goto done;
443 add_key_binding (&dst, config_key.func, c,
444 (desc) ? desc : _("no description"), config_key.r);
446 done:
447 return;
450 static struct known_key_s
452 wint_t c;
453 const char *name;
454 } known_keys[] =
457 KEY_UP, "up"},
459 KEY_DOWN, "down"},
461 KEY_LEFT, "left"},
463 KEY_RIGHT, "right"},
465 KEY_HOME, "home"},
467 KEY_END, "end"},
469 KEY_DC, "delete"},
471 KEY_PPAGE, "pgup"},
473 KEY_NPAGE, "pgdn"},
475 KEY_IC, "insert"},
477 ' ', "space"},
479 KEY_ESCAPE, "escape"},
481 '\n', "enter"},
483 0, NULL}
486 static wint_t
487 parse_key (const char *filename, int lines, int word, wchar_t ** key)
489 wchar_t *p = key ? *key : NULL;
490 wchar_t *orig = key ? *key : NULL;
491 wint_t c = 0;
492 int quote = 0;
494 if (!key || !wcslen (*key))
495 return 0;
497 if (*p == '\"' && !isspace (*(p+1)))
499 quote = 1;
500 p++;
503 if (*p == '<')
505 int i;
507 p++;
509 for (i = 0; known_keys[i].name; i++)
511 wchar_t *wc = str_to_wchar (known_keys[i].name);
513 if (!wcsncasecmp (p, wc, wcslen (wc)))
515 c = known_keys[i].c;
516 p += strlen (known_keys[i].name);
517 free (wc);
518 break;
521 free (wc);
524 if (!c)
526 if (*p == '^')
528 p++;
529 c = CTRL_KEY (*p++);
531 else if (*p == 'F' || *p == 'f')
533 char *str = wchar_to_str (++p);
535 c = KEY_F (atoi (str));
536 p += integer_len (atoi (str));
537 free (str);
541 if (!c)
542 c = *p++;
544 if (*p++ != '>')
545 errx (EXIT_FAILURE, _("%s(%i): parse error \"%ls\""), filename,
546 lines, orig);
548 else if (*p == '\\')
550 p++;
551 c = *p++;
553 else
554 c = *p++;
556 if (quote && *p != '\"')
557 errx (EXIT_FAILURE, _("%s(%i): parse error \"%ls\""), filename,
558 lines, orig);
559 else if (quote)
560 p++;
562 if (word && *p && !isspace (*p))
563 errx (EXIT_FAILURE, _("%s(%i): parse error \"%ls\""), filename,
564 lines, orig);
566 orig += wcslen (orig) - wcslen (p);
567 *key = orig;
568 return c;
571 static void
572 parse_key_binding (const char *filename, int lines, char *val)
574 char mode[64], func[64];
575 wchar_t desc[64] = { 0 };
576 wchar_t key[64];
577 int n;
578 int m = 0;
579 wint_t c = 0;
580 int f;
581 int i;
582 wchar_t *p;
583 char *str;
585 n = sscanf (val, "%s %ls %s %63lc", mode, key, func, desc);
587 if (n < 3)
588 errx (EXIT_FAILURE, _("%s(%i): too few arguments"), filename, lines);
590 if (strcasecmp (mode, "history") == 0)
591 m = MODE_HISTORY;
592 else if (strcasecmp (mode, "play") == 0)
593 m = MODE_PLAY;
594 else if (strcasecmp (mode, "edit") == 0)
595 m = MODE_EDIT;
596 else if (strcasecmp (mode, "any") == 0)
597 m = MODE_ANY;
598 else
599 errx (EXIT_FAILURE, _("%s(%i): invalid game mode \"%s\""), filename,
600 lines, mode);
602 p = key;
603 c = parse_key (filename, lines, 1, &p);
605 if (m != -1)
607 for (i = 0; global_keys[i]; i++)
609 if (global_keys[i]->c == c)
610 errx (EXIT_FAILURE,
611 _("%s(%i): key \"%ls\" conflicts with a global key"),
612 filename, lines, key);
616 for (f = -2, i = 0; config_keys[i].name; i++)
618 if (strcmp (config_keys[i].name, func) == 0 && config_keys[i].mode == m)
620 f = i;
621 break;
625 if (f == -2)
626 errx (EXIT_FAILURE, _("%s(%i): invalid command \"%s\""), filename,
627 lines, func);
629 str = wchar_to_str (desc);
631 switch (m)
633 case MODE_PLAY:
634 update_key (play_keys, config_keys[f], c, (n > 3) ? str : NULL);
635 break;
636 case MODE_HISTORY:
637 update_key (history_keys, config_keys[f], c, (n > 3) ? str : NULL);
638 break;
639 case MODE_EDIT:
640 update_key (edit_keys, config_keys[f], c, (n > 3) ? str : NULL);
641 break;
642 default:
643 update_key (global_keys, config_keys[f], c, (n > 3) ? str : NULL);
644 break;
647 free (str);
650 static wchar_t *
651 parse_macro_desc (const char *filename, int lines, wchar_t **val)
653 int quote = 0;
654 wchar_t *p;
655 wchar_t *buf = Malloc (256 * sizeof (wchar_t));
656 wchar_t *b = buf;
658 if (!buf)
659 return NULL;
661 for (p = *val; p && *p; p++)
663 if (*p == '\"')
665 if (quote)
667 p++;
668 break;
671 quote = 1;
672 continue;
674 else if (isspace (*p) && !quote)
675 break;
677 *b++ = *p;
680 if (!isspace (*p) || !*(p+1))
682 fprintf(stderr, _ ("%s(%i): parse error\n"), filename, lines);
683 free (buf);
684 return NULL;
687 while (isspace (*p))
688 p++;
690 *val = p;
691 *b = 0;
692 return buf;
695 static void
696 parse_macro (const char *filename, int lines, char *val)
698 char mode[16];
699 wchar_t keys[2048] = { 0 }, key[8];
700 int n;
701 int m;
702 wint_t c;
703 int i = 0;
704 wchar_t *p;
706 n = sscanf (val, "%s %ls %2047lc", mode, key, keys);
708 if (n != 3)
709 errx (EXIT_FAILURE, _("%s(%i): too few arguments"), filename, lines);
711 if (strcasecmp (mode, "history") == 0)
712 m = MODE_HISTORY;
713 else if (strcasecmp (mode, "play") == 0)
714 m = MODE_PLAY;
715 else if (strcasecmp (mode, "edit") == 0)
716 m = MODE_EDIT;
717 else if (strcasecmp (mode, "any") == 0)
718 m = -1;
719 else
720 errx (EXIT_FAILURE, _("%s(%i): invalid game mode \"%s\""), filename,
721 lines, mode);
723 p = key;
724 c = parse_key (filename, lines, 1, &p);
726 if (macros)
727 for (i = 0; macros[i]; i++);
729 macros = Realloc (macros, (i + 2) * sizeof (struct macro_s *));
730 macros[i] = Calloc (1, sizeof (struct macro_s));
731 macros[i]->c = c;
732 macros[i]->mode = m;
733 p = keys;
735 macros[i]->desc = parse_macro_desc (filename, lines, &p);
736 if (!macros[i]->desc)
737 exit (EXIT_FAILURE);
739 while ((c = parse_key (filename, lines, 0, &p)) != 0)
741 macros[i]->keys = Realloc (macros[i]->keys, (macros[i]->total + 2) *
742 sizeof (wint_t));
743 macros[i]->keys[macros[i]->total++] = c;
746 macros[++i] = NULL;
749 void
750 parse_rcfile (const char *filename)
752 FILE *fp;
753 char *line, buf[LINE_MAX];
754 int lines = 0;
755 char *altengine = NULL;
756 int init = 0;
757 int k = 0;
758 int c;
760 if ((fp = fopen (filename, "r")) == NULL)
761 err (EXIT_FAILURE, "%s", filename);
763 while ((line = fgets (buf, sizeof (buf), fp)) != NULL)
765 int n;
766 char var[30] = { 0 }, val[LINE_MAX - sizeof (var) - 1] =
769 char token[MAX_PGN_LINE_LEN + 1] = { 0 };
770 char value[MAX_PGN_LINE_LEN + 1] = { 0 };
771 char *p;
773 lines++;
774 line = trim (line);
776 if (!line[0] || line[0] == '#')
777 continue;
779 if ((n = sscanf (line, "%s %[^\n]", var, val)) != 2)
780 errx (EXIT_FAILURE, _("%s(%i): parse error %i"), filename, lines, n);
782 p = strdup (trim (val));
783 strncpy (val, p, sizeof (val) - 1);
784 free (p);
785 p = strdup (trim (var));
786 strncpy (var, p, sizeof (var) - 1);
787 free (p);
789 if (strcmp (var, "jump_count") == 0)
791 if (!isinteger (val))
792 errx (EXIT_FAILURE, _("%s(%i): value is not an integer"),
793 filename, lines);
795 config.jumpcount = atoi (val);
797 else if (strcmp (var, "engine_init") == 0)
799 config.einit =
800 Realloc (config.einit, (init + 2) * sizeof (wchar_t *));
801 config.einit[init++] = str_to_wchar (val);
802 config.einit[init] = NULL;
804 else if (strcmp (var, "pattern") == 0)
806 free (config.pattern);
807 config.pattern = strdup (val);
809 else if (strcmp (var, "mpl") == 0)
811 if (!isinteger (val))
812 errx (EXIT_FAILURE, _("%s(%i): value is not an integer"),
813 filename, lines);
814 pgn_config_set (PGN_MPL, atoi (val));
816 else if (strcmp (var, "stop_on_error") == 0)
817 pgn_config_set (PGN_STOP_ON_ERROR, on_or_off (filename, lines, val));
818 else if (strcmp (var, "tag") == 0)
820 if ((n = sscanf (val, "%s %s ", token, value)) < 1 || n > 2)
821 errx (EXIT_FAILURE, _("%s(%i): invalid value \"%s\""), filename,
822 lines, val);
824 if (n == 1)
825 value[0] = 0;
826 else
828 p = val + strlen (token);
829 strncpy (value, p, sizeof (value) - 1);
832 for (n = 0; n < strlen (token); n++)
834 if (!isalnum (token[n]) && token[n] != '_')
835 errx (EXIT_FAILURE,
836 _("%s(%i): token names must match 0-9A-Za-z_."),
837 filename, lines);
840 token[0] = toupper (token[0]);
841 pgn_tag_add (&config.tag, token, value);
843 else if (strcmp (var, "save_directory") == 0)
844 config.savedirectory = strdup (val);
845 else if (strcmp (var, "line_graphics") == 0)
846 config.linegraphics = on_or_off (filename, lines, val);
847 else if (strcmp (var, "save_prompt") == 0)
848 config.saveprompt = on_or_off (filename, lines, val);
849 else if (strcmp (var, "delete_prompt") == 0)
850 config.deleteprompt = on_or_off (filename, lines, val);
851 else if (strcmp (var, "valid_moves") == 0)
852 config.validmoves = on_or_off (filename, lines, val);
853 else if (strcmp (var, "board_details") == 0)
854 config.details = on_or_off (filename, lines, val);
855 else if (strcmp (var, "show_attacks") == 0)
856 config.showattacks = on_or_off (filename, lines, val);
857 else if (strcmp (var, "coords_y_left") == 0)
858 config.coordsyleft = on_or_off (filename, lines, val);
859 else if (strcmp (var, "fm_polyglot") == 0)
860 config.fmpolyglot = on_or_off (filename, lines, val);
861 else if (strcmp (var, "board_left") == 0)
862 config.boardleft = on_or_off (filename, lines, val);
863 else if (strcmp (var, "exit_dialog_box") == 0)
864 config.exitdialogbox = on_or_off (filename, lines, val);
865 else if (strcmp (var, "engine_cmd_blacktag") == 0)
866 config.enginecmdblacktag = on_or_off (filename, lines, val);
867 else if (strcmp (var, "board_prev_move") == 0)
868 config.bprevmove = on_or_off (filename, lines, val);
869 else if (strcmp (var, "strict_castling") == 0)
870 pgn_config_set (PGN_STRICT_CASTLING,
871 on_or_off (filename, lines, val));
872 else if (strcmp (var, "engine_cmd") == 0)
873 altengine = strdup (val);
874 else if (strcmp (var, "engine_protocol") == 0)
876 if (!isinteger (val))
877 errx (EXIT_FAILURE, _("%s(%i): value is not an integer"),
878 filename, lines);
880 config.engine_protocol = atoi (val);
882 if (config.engine_protocol != 1 && config.engine_protocol != 2)
883 errx (EXIT_FAILURE, _("%s(%i): invalid value"), filename, lines);
885 else if (strcmp (var, "engine_timeout") == 0)
886 config.engine_timeout = atoi (val);
887 else if (strcmp (var, "utf8_pieces") == 0)
888 config.utf8_pieces = on_or_off (filename, lines, val);
889 else if (strcmp (var, "turn_cmd") == 0)
890 config.turn_cmd = strdup (val);
891 else if (strcmp (var, "color_board_window") == 0)
892 parse_color (filename, lines, val, &config.color[CONF_BDWINDOW]);
893 else if (strcmp (var, "color_board_selected") == 0)
894 parse_color (filename, lines, val, &config.color[CONF_BSELECTED]);
895 else if (strcmp (var, "color_board_white_moves") == 0)
896 parse_color (filename, lines, val, &config.color[CONF_BMOVESW]);
897 else if (strcmp (var, "color_board_black_moves") == 0)
898 parse_color (filename, lines, val, &config.color[CONF_BMOVESB]);
899 else if (strcmp (var, "color_board_count") == 0)
900 parse_color (filename, lines, val, &config.color[CONF_BCOUNT]);
901 else if (strcmp (var, "color_board_cursor") == 0)
902 parse_color (filename, lines, val, &config.color[CONF_BCURSOR]);
903 else if (strcmp (var, "color_board_black") == 0)
904 parse_color (filename, lines, val, &config.color[CONF_BBLACK]);
905 else if (strcmp (var, "color_board_white") == 0)
906 parse_color (filename, lines, val, &config.color[CONF_BWHITE]);
907 else if (strcmp (var, "color_board_graphics") == 0)
908 parse_color (filename, lines, val, &config.color[CONF_BGRAPHICS]);
909 else if (strcmp (var, "color_board_coords") == 0)
910 parse_color (filename, lines, val, &config.color[CONF_BCOORDS]);
911 else if (strcmp (var, "color_board_castling") == 0)
912 parse_color (filename, lines, val, &config.color[CONF_BCASTLING]);
913 else if (strcmp (var, "color_board_enpassant") == 0)
914 parse_color (filename, lines, val, &config.color[CONF_BENPASSANT]);
915 else if (strcmp (var, "color_board_attack") == 0)
916 parse_color (filename, lines, val, &config.color[CONF_BATTACK]);
917 else if (strcmp (var, "color_board_prev_move") == 0)
918 parse_color (filename, lines, val, &config.color[CONF_BPREVMOVE]);
919 else if (strcmp (var, "color_status_window") == 0)
920 parse_color (filename, lines, val, &config.color[CONF_SWINDOW]);
921 else if (strcmp (var, "color_status_title") == 0)
922 parse_color (filename, lines, val, &config.color[CONF_STITLE]);
923 else if (strcmp (var, "color_status_border") == 0)
924 parse_color (filename, lines, val, &config.color[CONF_SBORDER]);
925 else if (strcmp (var, "color_status_notify") == 0)
926 parse_color (filename, lines, val, &config.color[CONF_SNOTIFY]);
927 else if (strcmp (var, "color_status_engine") == 0)
928 parse_color (filename, lines, val, &config.color[CONF_SENGINE]);
929 else if (strcmp (var, "color_tag_window") == 0)
930 parse_color (filename, lines, val, &config.color[CONF_TWINDOW]);
931 else if (strcmp (var, "color_tag_title") == 0)
932 parse_color (filename, lines, val, &config.color[CONF_TTITLE]);
933 else if (strcmp (var, "color_tag_border") == 0)
934 parse_color (filename, lines, val, &config.color[CONF_TBORDER]);
935 else if (strcmp (var, "color_history_window") == 0)
936 parse_color (filename, lines, val, &config.color[CONF_HWINDOW]);
937 else if (strcmp (var, "color_history_title") == 0)
938 parse_color (filename, lines, val, &config.color[CONF_HTITLE]);
939 else if (strcmp (var, "color_history_border") == 0)
940 parse_color (filename, lines, val, &config.color[CONF_HBORDER]);
941 else if (strcmp (var, "color_message_window") == 0)
942 parse_color (filename, lines, val, &config.color[CONF_MWINDOW]);
943 else if (strcmp (var, "color_message_title") == 0)
944 parse_color (filename, lines, val, &config.color[CONF_MTITLE]);
945 else if (strcmp (var, "color_message_border") == 0)
946 parse_color (filename, lines, val, &config.color[CONF_MBORDER]);
947 else if (strcmp (var, "color_message_prompt") == 0)
948 parse_color (filename, lines, val, &config.color[CONF_MPROMPT]);
949 else if (strcmp (var, "color_input_window") == 0)
950 parse_color (filename, lines, val, &config.color[CONF_IWINDOW]);
951 else if (strcmp (var, "color_input_title") == 0)
952 parse_color (filename, lines, val, &config.color[CONF_ITITLE]);
953 else if (strcmp (var, "color_input_border") == 0)
954 parse_color (filename, lines, val, &config.color[CONF_IBORDER]);
955 else if (strcmp (var, "color_input_prompt") == 0)
956 parse_color (filename, lines, val, &config.color[CONF_IPROMPT]);
957 else if (strcmp (var, "color_menu") == 0)
958 parse_color (filename, lines, val, &config.color[CONF_MENU]);
959 else if (strcmp (var, "color_menu_selected") == 0)
960 parse_color (filename, lines, val, &config.color[CONF_MENUS]);
961 else if (strcmp (var, "color_menu_highlight") == 0)
962 parse_color (filename, lines, val, &config.color[CONF_MENUH]);
963 else if (strcmp (var, "color_menu_graphics") == 0)
964 parse_color (filename, lines, val,
965 &config.color[CONF_HISTORY_MENU_LG]);
966 else if (strcmp (var, "bind") == 0)
967 parse_key_binding (filename, lines, val);
968 else if (strcmp (var, "macro") == 0)
969 parse_macro (filename, lines, val);
970 else if (strcmp (var, "cbind") == 0)
972 config.keys = Realloc (config.keys, (k + 2) *
973 sizeof (struct config_key_s *));
974 config.keys[k] = Calloc (1, sizeof (struct config_key_s));
975 p = val;
976 n = 0;
978 while (*p && !isspace (*p))
979 p++, n++;
981 c = *p;
982 *p = 0;
983 p -= n;
985 if (strcasecmp (p, "none") == 0)
986 config.keys[k]->type = KEY_DEFAULT;
987 else if (strcasecmp (p, "repeat") == 0)
988 config.keys[k]->type = KEY_REPEAT;
989 else if (strcasecmp (p, "set") == 0)
990 config.keys[k]->type = KEY_SET;
991 else
992 errx (EXIT_FAILURE, _("%s(%i): invalid value \"%s\""), filename,
993 lines, p);
995 p = val + n;
996 *p = c;
998 while (*p && isspace (*p))
999 p++;
1001 config.keys[k]->c = *p++;
1003 while (isspace (*p))
1004 p++;
1006 config.keys[k++]->str = str_to_wchar (p);
1007 config.keys[k] = NULL;
1009 else
1010 errx (EXIT_FAILURE, _("%s(%i): invalid parameter \"%s\""), filename,
1011 lines, var);
1014 fclose (fp);
1016 if (altengine)
1018 free (config.engine_cmd);
1019 config.engine_cmd = NULL;
1020 config.engine_cmd = altengine;
1023 if (config.enginecmdblacktag)
1024 pgn_tag_add (&config.tag, (char *) "Black", config.engine_cmd);
1027 static struct key_s *
1028 find_key (struct key_s **keys, key_func f)
1030 int i;
1032 for (i = 0; keys[i]; i++)
1034 if (keys[i]->f == f)
1035 return keys[i];
1038 return NULL;
1041 const wchar_t *
1042 key_lookup (struct key_s **keys, key_func f)
1044 struct key_s *k = find_key (keys, f);
1046 return k ? k->key : NULL;
1049 wint_t
1050 keycode_lookup (struct key_s **keys, key_func f)
1052 struct key_s *k = find_key (keys, f);
1054 return k ? k->c : 0;