Fix build failure.
[cboard.git] / src / tags.c
blob10cdf0ef19d20c746e29349deb9e8783899199a5
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2019 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 <sys/time.h>
27 #include <time.h>
28 #include <limits.h>
29 #include <errno.h>
31 #ifdef HAVE_STRINGS_H
32 #include <strings.h>
33 #endif
35 #include "common.h"
36 #include "conf.h"
37 #include "colors.h"
38 #include "strings.h"
39 #include "window.h"
40 #include "input.h"
41 #include "misc.h"
42 #include "message.h"
43 #include "menu.h"
44 #include "keys.h"
45 #include "rcfile.h"
47 static struct country_codes
49 char code[4];
50 char country[64];
51 } *ccodes;
53 static int
54 init_country_codes ()
56 FILE *fp;
57 char line[LINE_MAX], *s;
58 int cindex = 0;
60 if ((fp = fopen (config.ccfile, "r")) == NULL)
62 cmessage (ERROR_STR, ANY_KEY_STR, "%s: %s", config.ccfile,
63 strerror (errno));
64 return 1;
67 while ((s = fgets (line, sizeof (line), fp)) != NULL)
69 char *tmp;
71 if ((tmp = strsep (&s, " ")) == NULL)
72 continue;
74 s = trim (s);
75 tmp = trim (tmp);
77 if (!s || !tmp)
78 continue;
80 ccodes = Realloc (ccodes, (cindex + 2) * sizeof (struct country_codes));
81 strncpy (ccodes[cindex].code, tmp, sizeof (ccodes[cindex].code));
82 ccodes[cindex].code[sizeof (ccodes[cindex].code) - 1] = 0;
83 strncpy (ccodes[cindex].country, s, sizeof (ccodes[cindex].country));
84 ccodes[cindex].country[sizeof (ccodes[cindex].country) - 1] = 0;
85 cindex++;
88 memset (&ccodes[cindex], '\0', sizeof (struct country_codes));
89 fclose (fp);
90 return 0;
93 static struct menu_item_s **
94 get_cc_items (WIN * win)
96 int i;
97 struct menu_input_s *m = win->data;
98 struct menu_item_s **items = m->items;
100 if (items)
102 for (i = 0; items[i]; i++)
103 free (items[i]);
106 for (i = 0; ccodes[i].code[0]; i++)
108 items = Realloc (items, (i + 2) * sizeof (struct menu_item_s *));
109 items[i] = Malloc (sizeof (struct menu_item_s));
110 items[i]->name = ccodes[i].code;
111 items[i]->value = ccodes[i].country;
112 items[i]->selected = 0;
115 items[i] = NULL;
116 m->total = i;
117 m->items = items;
118 m->nofree = 1;
119 return items;
122 static void
123 do_cc_help (struct menu_input_s *m)
125 message (_("Country Code Keys"), ANY_KEY_STR, "%s",
126 _(" UP/DOWN - previous/next menu item\n"
127 " HOME/END - first/last menu item\n"
128 " PGDN/PGUP - next/previous page\n"
129 " a-zA-Z0-9 - jump to item\n"
130 " ENTER - select item\n" " ESCAPE - cancel"));
133 static void
134 do_cc_abort (struct menu_input_s *m)
136 pushkey = -1;
139 static void
140 do_cc_finalize (WIN * win)
142 struct input_s *in = win->data;
143 TAG *t = (TAG *) in->arg;
145 set_field_buffer (in->fields[0], 0, t->value);
148 static void
149 do_cc_save (struct menu_input_s *m)
151 struct input_s *in = m->data;
152 TAG *t = (TAG *) in->arg;
153 int len = strlen (m->items[m->selected]->name);
155 t->value = Realloc (t->value, len + 1);
156 strcpy (t->value, m->items[m->selected]->name);
157 pushkey = -1;
160 static void
161 cc_print (WIN * win)
163 struct menu_input_s *m = win->data;
165 mvwprintw (win->w, m->print_line, 1, "%s %-*s", m->item->name,
166 win->cols - 6, m->item->value);
169 static void
170 country_codes (void *arg)
172 struct menu_key_s **keys = NULL;
174 if (!ccodes)
176 if (init_country_codes ())
177 return;
180 add_menu_key (&keys, keycode_lookup (global_keys, do_global_help),
181 do_cc_help);
182 add_menu_key (&keys, KEY_ESCAPE, do_cc_abort);
183 add_menu_key (&keys, '\n', do_cc_save);
184 construct_menu (0, 0, -1, -1, _("Country Codes"), 0, get_cc_items, keys,
185 arg, cc_print, do_cc_finalize, NULL);
186 return;
189 void
190 add_custom_tags (TAG *** t)
192 int i;
193 int total = pgn_tag_total (config.tag);
195 if (!config.tag)
196 return;
198 for (i = 0; i < total; i++)
199 pgn_tag_add (t, config.tag[i]->name, config.tag[i]->value);
201 pgn_tag_sort (*t);
204 static struct menu_item_s **
205 get_tag_items (WIN * win)
207 int i, n;
208 struct menu_input_s *m = win->data;
209 struct menu_item_s **items = m->items;
210 TAG **t = (m->data) ? m->data : gp->tag;
212 if (items)
214 for (i = 0; items[i]; i++)
215 free (items[i]);
218 n = pgn_tag_total (t);
220 for (i = 0; i < n; i++)
222 items = Realloc (items, (i + 2) * sizeof (struct menu_item_s *));
223 items[i] = Malloc (sizeof (struct menu_item_s));
224 items[i]->name = t[i]->name;
225 items[i]->value = t[i]->value;
226 items[i]->selected = 0;
229 items[i] = NULL;
230 m->total = i;
231 m->items = items;
232 m->nofree = 1;
233 return items;
236 static void
237 edit_tag_add_fen (struct menu_input_s *m)
239 TAG **t = m->data;
240 struct userdata_s *d = gp->data;
241 char *fen = pgn_game_to_fen (gp, d->b);
243 pgn_tag_add (&t, (char *) "FEN", fen);
244 free (fen);
245 m->data = t;
248 static void
249 edit_tag_abort (struct menu_input_s *m)
251 TAG **t = m->data;
253 pgn_tag_free (t);
254 m->data = NULL;
255 pushkey = -1;
256 update_status_notify (gp, _("Tag edit aborted."));
259 static void
260 edit_tag_add_finalize (WIN * w)
262 struct input_data_s *in = w->data;
263 char *name = in->moredata;
264 char *value = in->str;
265 struct menu_input_s *m = in->data;
266 TAG **t = m->data;
267 char buf[32];
268 struct tm *tm;
269 time_t now;
270 char *tmp;
271 int count;
273 if (!value || !*value)
275 if (strcasecmp (name, "Round") == 0)
276 value = (char *) "-";
277 else if (strcasecmp (name, "Result") == 0)
278 value = (char *) "*";
279 else if (strcasecmp (name, "Date") == 0)
281 time (&now);
282 tm = localtime (&now);
283 strftime (buf, sizeof (buf), PGN_TIME_FORMAT, tm);
284 value = buf;
286 else
287 value = (char *) "?";
290 tmp = trim_multi (value);
291 count = pgn_tag_total (t);
292 pgn_tag_add (&t, name, tmp);
293 free (tmp);
294 m->data = t;
296 if (count != pgn_tag_total (t))
297 m->selected = m->total;
299 if (in->str)
300 free (in->str);
302 free (name);
303 free (in);
304 pushkey = REFRESH_MENU;
307 static void
308 set_menu_stuff (TAG ** t, char *name, char **init, int *type,
309 int *lines, input_func ** func, wint_t * key, char **eprompt,
310 void **arg)
312 int n;
313 char *p;
315 if ((n = pgn_tag_find (t, name)) != -1)
317 p = t[n]->value;
318 *init = p;
321 if (strcasecmp (name, "Date") == 0)
323 *type = FIELD_TYPE_PGN_DATE;
324 *lines = 1;
326 else if (strcasecmp (name, "Site") == 0)
328 *func = country_codes;
329 *key = CTRL_KEY ('t');
330 *eprompt = _("Type CTRL-t for country codes");
331 *arg = t[n];
333 else if (strcasecmp (name, "Round") == 0)
335 *type = FIELD_TYPE_PGN_ROUND;
336 *lines = 1;
338 else if (strcasecmp (name, "Result") == 0)
340 *type = FIELD_TYPE_PGN_RESULT;
341 *lines = 1;
345 static void
346 edit_tag_value (struct menu_input_s *m)
348 char buf[COLS - 4];
349 struct input_data_s *in = Calloc (1, sizeof (struct input_data_s));
350 char *init = NULL;
351 TAG **t = m->data;
352 char *name;
353 int type = -1;
354 input_func *func = NULL;
355 wint_t key = 0;
356 char *eprompt = NULL;
357 void *arg = NULL;
358 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
359 wchar_t *wc;
361 in->data = m;
362 name = strdup (t[m->selected]->name);
363 in->moredata = name;
364 in->efunc = edit_tag_add_finalize;
365 wc = str_to_wchar (name);
366 snprintf (buf, sizeof (buf), "%s \"%ls\"", _("Editing Tag"), wc);
367 free (wc);
368 set_menu_stuff (t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
369 construct_input (buf, init, lines, 0, eprompt, func, arg, key, in, -1,
370 NULL, type);
373 static void
374 edit_tag_add_name_finalize (WIN * w)
376 struct input_data_s *in = w->data;
377 struct input_data_s *inv;
378 struct menu_input_s *m = in->data;
379 TAG **t = m->data;
380 char buf[COLS - 4];
381 char *init = NULL;
382 char *name;
383 wint_t key = 0;
384 int type = -1;
385 input_func *func = NULL;
386 char *eprompt = NULL;
387 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
388 void *arg = NULL;
389 wchar_t *wc;
391 if (!in->str)
392 return;
394 name = strdup (in->str);
395 inv = Calloc (1, sizeof (struct input_data_s));
396 inv->efunc = edit_tag_add_finalize;
397 inv->data = in->data;
398 inv->moredata = name;
399 free (in->str);
400 free (in);
401 wc = str_to_wchar (name);
402 snprintf (buf, sizeof (buf), "%s \"%ls\"", _("Editing Tag"), wc);
403 free (wc);
404 set_menu_stuff (t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
405 construct_input (buf, init, lines, 0, eprompt, func, arg, key, inv, -1,
406 NULL, type);
409 static void
410 edit_tag_add (struct menu_input_s *m)
412 struct input_data_s *in = Calloc (1, sizeof (struct input_s));
414 in->data = m;
415 in->efunc = edit_tag_add_name_finalize;
416 construct_input (_("New Tag Name"), NULL, 1, 1, NULL, NULL, NULL, 0, in, -1,
417 NULL, FIELD_TYPE_PGN_TAG_NAME);
420 static void
421 edit_tag_remove (struct menu_input_s *m)
423 TAG **data = NULL;
424 TAG **t = m->data;
425 int i, n = pgn_tag_total (t);
427 if (m->selected < 7)
429 cmessage (NULL, ANY_KEY_STR, "%s",
430 _("Cannot remove the Seven Tag Roster"));
431 return;
434 for (i = 0; i < n; i++)
436 if (i == m->selected)
437 continue;
439 pgn_tag_add (&data, t[i]->name, t[i]->value);
442 pgn_tag_free (t);
443 m->data = data;
444 m->update = 1;
447 static void
448 edit_tag_add_custom (struct menu_input_s *m)
450 TAG **t = m->data;
452 add_custom_tags (&t);
453 m->data = t;
456 static void
457 edit_tag_save (struct menu_input_s *m)
459 TAG **t = m->data;
460 struct userdata_s *d = gp->data;
462 if (!m->data)
463 return;
465 pgn_tag_free (gp->tag);
466 pgn_tag_sort (t);
467 gp->tag = t;
468 pushkey = -1;
469 SET_FLAG (d->flags, CF_MODIFIED);
472 * In case of editing a FEN tag. Must not be MODE_PLAY. Also updates the
473 * games ply count for the fifty move draw rule.
475 if (d->mode != MODE_PLAY)
476 pgn_board_update (gp, d->b, gp->hindex);
479 static void
480 edit_tag_help (struct menu_input_s *m)
482 message (_("Tag Editing Keys"), ANY_KEY_STR,
483 _(" UP/DOWN - previous/next menu item\n"
484 " HOME/END - first/last menu item\n"
485 " PGDN/PGUP - next/previous page\n"
486 " a-zA-Z0-9 - jump to item\n"
487 " ENTER - edit select item\n"
488 " CTRL-a - add an entry\n"
489 " CTRL-f - add FEN tag from current position\n"
490 " CTRL-r - remove selected entry\n"
491 " CTRL-t - add custom tags\n"
492 " CTRL-x - quit with changes\n"
493 " ESCAPE - quit without changes"));
496 static void
497 view_tag_help (struct menu_input_s *m)
499 message (_("Tag Viewing Keys"), ANY_KEY_STR,
500 _(" UP/DOWN - previous/next menu item\n"
501 " HOME/END - first/last menu item\n"
502 " PGDN/PGUP - next/previous page\n"
503 " a-zA-Z0-9 - jump to item\n"
504 " ENTER - view selected item\n" " ESCAPE - cancel"));
507 static void
508 view_tag_quit (struct menu_input_s *m)
510 pushkey = -1;
513 static void
514 view_tag_value (struct menu_input_s *m)
516 struct menu_item_s *item = m->items[m->selected];
517 char buf[COLS - 4];
518 wchar_t *wc = str_to_wchar (item->name);
520 snprintf (buf, sizeof (buf), "%s \"%ls\"", _("Viewing Tag"), wc);
521 free (wc);
522 construct_message (buf, ANY_KEY_STR, 0, 1, NULL,
523 NULL, NULL, NULL, 0, 0, NULL, "%s", item->value);
526 static void
527 tag_print (WIN * win)
529 int i, len = 0, n;
530 struct menu_input_s *m = win->data;
531 wchar_t *wc;
533 for (i = 0; m->items[i]; i++)
535 wc = translate_tag_name (m->items[i]->name);
536 n = wcslen (wc);
537 free (wc);
538 if (len < n)
539 len = n;
542 wc = translate_tag_name (m->item->name);
543 mvwprintw (win->w, m->print_line, 1, "%ls", wc);
545 for (n = wcslen (wc) + 1; n <= len; n++)
546 mvwprintw (win->w, m->print_line, n, "%c", '.');
548 free (wc);
549 mvwprintw (win->w, m->print_line, n, ": ");
550 i = win->cols - n - 3;
551 wc = str_etc (m->item->value, i, 0);
552 mvwprintw (win->w, m->print_line, n + 2, "%-*ls", i, wc);
553 free (wc);
555 if (m->update)
557 wmove (stdscr, 0, 0);
558 wclrtobot (stdscr);
559 update_all (gp);
560 m->update = 0;
564 void
565 edit_tags (GAME g, BOARD b, int edit)
567 struct menu_key_s **keys = NULL;
568 TAG **data = NULL;
569 int i;
571 if (edit)
573 for (i = 0; gp->tag[i]; i++)
574 pgn_tag_add (&data, gp->tag[i]->name, gp->tag[i]->value);
576 add_menu_key (&keys, '\n', edit_tag_value);
577 add_menu_key (&keys, CTRL_KEY ('f'), edit_tag_add_fen);
578 add_menu_key (&keys, CTRL_KEY ('a'), edit_tag_add);
579 add_menu_key (&keys, CTRL_KEY ('r'), edit_tag_remove);
580 add_menu_key (&keys, CTRL_KEY ('t'), edit_tag_add_custom);
581 add_menu_key (&keys, CTRL_KEY ('x'), edit_tag_save);
582 add_menu_key (&keys, KEY_ESCAPE, edit_tag_abort);
583 add_menu_key (&keys, keycode_lookup (global_keys, do_global_help),
584 edit_tag_help);
586 else
588 add_menu_key (&keys, '\n', view_tag_value);
589 data = gp->tag;
590 add_menu_key (&keys, KEY_ESCAPE, view_tag_quit);
591 add_menu_key (&keys, keycode_lookup (global_keys, do_global_help),
592 view_tag_help);
595 construct_menu (0, 0, -1, -1,
596 (edit) ? _("Editing Roster Tags") :
597 _("Viewing Roster Tags"), 0, get_tag_items, keys, data,
598 tag_print, NULL, NULL);