Update URL's to GitLab.
[cboard.git] / src / tags.c
blob753fae4c337769c27ca9ebb4ed78d2a5cf2d8d83
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 <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"
46 static struct country_codes
48 char code[4];
49 char country[64];
50 } *ccodes;
52 static int
53 init_country_codes ()
55 FILE *fp;
56 char line[LINE_MAX], *s;
57 int cindex = 0;
59 if ((fp = fopen (config.ccfile, "r")) == NULL)
61 cmessage (ERROR_STR, ANY_KEY_STR, "%s: %s", config.ccfile,
62 strerror (errno));
63 return 1;
66 while ((s = fgets (line, sizeof (line), fp)) != NULL)
68 char *tmp;
70 if ((tmp = strsep (&s, " ")) == NULL)
71 continue;
73 s = trim (s);
74 tmp = trim (tmp);
76 if (!s || !tmp)
77 continue;
79 ccodes = Realloc (ccodes, (cindex + 2) * sizeof (struct country_codes));
80 strncpy (ccodes[cindex].code, tmp, sizeof (ccodes[cindex].code));
81 ccodes[cindex].code[sizeof (ccodes[cindex].code) - 1] = 0;
82 strncpy (ccodes[cindex].country, s, sizeof (ccodes[cindex].country));
83 ccodes[cindex].country[sizeof (ccodes[cindex].country) - 1] = 0;
84 cindex++;
87 memset (&ccodes[cindex], '\0', sizeof (struct country_codes));
88 fclose (fp);
89 return 0;
92 static struct menu_item_s **
93 get_cc_items (WIN * win)
95 int i;
96 struct menu_input_s *m = win->data;
97 struct menu_item_s **items = m->items;
99 if (items)
101 for (i = 0; items[i]; i++)
102 free (items[i]);
105 for (i = 0; ccodes[i].code[0]; i++)
107 items = Realloc (items, (i + 2) * sizeof (struct menu_item_s *));
108 items[i] = Malloc (sizeof (struct menu_item_s));
109 items[i]->name = ccodes[i].code;
110 items[i]->value = ccodes[i].country;
111 items[i]->selected = 0;
114 items[i] = NULL;
115 m->total = i;
116 m->items = items;
117 m->nofree = 1;
118 return items;
121 static void
122 do_cc_help (struct menu_input_s *m)
124 message (_("Country Code Keys"), ANY_KEY_STR, "%s",
125 _(" UP/DOWN - previous/next menu item\n"
126 " HOME/END - first/last menu item\n"
127 " PGDN/PGUP - next/previous page\n"
128 " a-zA-Z0-9 - jump to item\n"
129 " ENTER - select item\n" " ESCAPE - cancel"));
132 static void
133 do_cc_abort (struct menu_input_s *m)
135 pushkey = -1;
138 static void
139 do_cc_finalize (WIN * win)
141 struct input_s *in = win->data;
142 TAG *t = (TAG *) in->arg;
144 set_field_buffer (in->fields[0], 0, t->value);
147 static void
148 do_cc_save (struct menu_input_s *m)
150 struct input_s *in = m->data;
151 TAG *t = (TAG *) in->arg;
152 int len = strlen (m->items[m->selected]->name);
154 t->value = Realloc (t->value, len + 1);
155 strcpy (t->value, m->items[m->selected]->name);
156 pushkey = -1;
159 static void
160 cc_print (WIN * win)
162 struct menu_input_s *m = win->data;
164 mvwprintw (win->w, m->print_line, 1, "%s %-*s", m->item->name,
165 win->cols - 6, m->item->value);
168 static void
169 country_codes (void *arg)
171 struct menu_key_s **keys = NULL;
173 if (!ccodes)
175 if (init_country_codes ())
176 return;
179 add_menu_key (&keys, KEY_F (1), do_cc_help);
180 add_menu_key (&keys, KEY_ESCAPE, do_cc_abort);
181 add_menu_key (&keys, '\n', do_cc_save);
182 construct_menu (0, 0, -1, -1, _("Country Codes"), 0, get_cc_items, keys,
183 arg, cc_print, do_cc_finalize, NULL);
184 return;
187 void
188 add_custom_tags (TAG *** t)
190 int i;
191 int total = pgn_tag_total (config.tag);
193 if (!config.tag)
194 return;
196 for (i = 0; i < total; i++)
197 pgn_tag_add (t, config.tag[i]->name, config.tag[i]->value);
199 pgn_tag_sort (*t);
202 static struct menu_item_s **
203 get_tag_items (WIN * win)
205 int i, n;
206 struct menu_input_s *m = win->data;
207 struct menu_item_s **items = m->items;
208 TAG **t = (m->data) ? m->data : gp->tag;
210 if (items)
212 for (i = 0; items[i]; i++)
213 free (items[i]);
216 n = pgn_tag_total (t);
218 for (i = 0; i < n; i++)
220 items = Realloc (items, (i + 2) * sizeof (struct menu_item_s *));
221 items[i] = Malloc (sizeof (struct menu_item_s));
222 items[i]->name = t[i]->name;
223 items[i]->value = t[i]->value;
224 items[i]->selected = 0;
227 items[i] = NULL;
228 m->total = i;
229 m->items = items;
230 m->nofree = 1;
231 return items;
234 static void
235 edit_tag_add_fen (struct menu_input_s *m)
237 TAG **t = m->data;
238 struct userdata_s *d = gp->data;
239 char *fen = pgn_game_to_fen (gp, d->b);
241 pgn_tag_add (&t, (char *) "FEN", fen);
242 free (fen);
243 m->data = t;
246 static void
247 edit_tag_abort (struct menu_input_s *m)
249 TAG **t = m->data;
251 pgn_tag_free (t);
252 m->data = NULL;
253 pushkey = -1;
254 update_status_notify (gp, _("Tag edit aborted."));
257 static void
258 edit_tag_add_finalize (WIN * w)
260 struct input_data_s *in = w->data;
261 char *name = in->moredata;
262 char *value = in->str;
263 struct menu_input_s *m = in->data;
264 TAG **t = m->data;
265 char buf[32];
266 struct tm *tm;
267 time_t now;
268 char *tmp;
269 int count;
271 if (!value || !*value)
273 if (strcasecmp (name, "Round") == 0)
274 value = (char *) "-";
275 else if (strcasecmp (name, "Result") == 0)
276 value = (char *) "*";
277 else if (strcasecmp (name, "Date") == 0)
279 time (&now);
280 tm = localtime (&now);
281 strftime (buf, sizeof (buf), PGN_TIME_FORMAT, tm);
282 value = buf;
284 else
285 value = (char *) "?";
288 tmp = trim_multi (value);
289 count = pgn_tag_total (t);
290 pgn_tag_add (&t, name, tmp);
291 free (tmp);
292 m->data = t;
294 if (count != pgn_tag_total (t))
295 m->selected = m->total;
297 if (in->str)
298 free (in->str);
300 free (name);
301 free (in);
302 pushkey = REFRESH_MENU;
305 static void
306 set_menu_stuff (TAG ** t, char *name, char **init, int *type,
307 int *lines, input_func ** func, wint_t * key, char **eprompt,
308 void **arg)
310 int n;
311 char *p;
313 if ((n = pgn_tag_find (t, name)) != -1)
315 p = t[n]->value;
316 *init = p;
319 if (strcasecmp (name, "Date") == 0)
321 *type = FIELD_TYPE_PGN_DATE;
322 *lines = 1;
324 else if (strcasecmp (name, "Site") == 0)
326 *func = country_codes;
327 *key = CTRL_KEY ('t');
328 *eprompt = _("Type CTRL-t for country codes");
329 *arg = t[n];
331 else if (strcasecmp (name, "Round") == 0)
333 *type = FIELD_TYPE_PGN_ROUND;
334 *lines = 1;
336 else if (strcasecmp (name, "Result") == 0)
338 *type = FIELD_TYPE_PGN_RESULT;
339 *lines = 1;
343 static void
344 edit_tag_value (struct menu_input_s *m)
346 char buf[COLS - 4];
347 struct input_data_s *in = Calloc (1, sizeof (struct input_data_s));
348 char *init = NULL;
349 TAG **t = m->data;
350 char *name;
351 int type = -1;
352 input_func *func = NULL;
353 wint_t key = 0;
354 char *eprompt = NULL;
355 void *arg = NULL;
356 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
357 wchar_t *wc;
359 in->data = m;
360 name = strdup (t[m->selected]->name);
361 in->moredata = name;
362 in->efunc = edit_tag_add_finalize;
363 wc = str_to_wchar (name);
364 snprintf (buf, sizeof (buf), "%s \"%ls\"", _("Editing Tag"), wc);
365 free (wc);
366 set_menu_stuff (t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
367 construct_input (buf, init, lines, 0, eprompt, func, arg, key, in, -1,
368 NULL, type);
371 static void
372 edit_tag_add_name_finalize (WIN * w)
374 struct input_data_s *in = w->data;
375 struct input_data_s *inv;
376 struct menu_input_s *m = in->data;
377 TAG **t = m->data;
378 char buf[COLS - 4];
379 char *init = NULL;
380 char *name;
381 wint_t key = 0;
382 int type = -1;
383 input_func *func = NULL;
384 char *eprompt = NULL;
385 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
386 void *arg = NULL;
387 wchar_t *wc;
389 if (!in->str)
390 return;
392 name = strdup (in->str);
393 inv = Calloc (1, sizeof (struct input_data_s));
394 inv->efunc = edit_tag_add_finalize;
395 inv->data = in->data;
396 inv->moredata = name;
397 free (in->str);
398 free (in);
399 wc = str_to_wchar (name);
400 snprintf (buf, sizeof (buf), "%s \"%ls\"", _("Editing Tag"), wc);
401 free (wc);
402 set_menu_stuff (t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
403 construct_input (buf, init, lines, 0, eprompt, func, arg, key, inv, -1,
404 NULL, type);
407 static void
408 edit_tag_add (struct menu_input_s *m)
410 struct input_data_s *in = Calloc (1, sizeof (struct input_s));
412 in->data = m;
413 in->efunc = edit_tag_add_name_finalize;
414 construct_input (_("New Tag Name"), NULL, 1, 1, NULL, NULL, NULL, 0, in, -1,
415 NULL, FIELD_TYPE_PGN_TAG_NAME);
418 static void
419 edit_tag_remove (struct menu_input_s *m)
421 TAG **data = NULL;
422 TAG **t = m->data;
423 int i, n = pgn_tag_total (t);
425 if (m->selected < 7)
427 cmessage (NULL, ANY_KEY_STR, "%s",
428 _("Cannot remove the Seven Tag Roster"));
429 return;
432 for (i = 0; i < n; i++)
434 if (i == m->selected)
435 continue;
437 pgn_tag_add (&data, t[i]->name, t[i]->value);
440 pgn_tag_free (t);
441 m->data = data;
442 m->update = 1;
445 static void
446 edit_tag_add_custom (struct menu_input_s *m)
448 TAG **t = m->data;
450 add_custom_tags (&t);
451 m->data = t;
454 static void
455 edit_tag_save (struct menu_input_s *m)
457 TAG **t = m->data;
458 struct userdata_s *d = gp->data;
460 if (!m->data)
461 return;
463 pgn_tag_free (gp->tag);
464 pgn_tag_sort (t);
465 gp->tag = t;
466 pushkey = -1;
467 SET_FLAG (d->flags, CF_MODIFIED);
470 * In case of editing a FEN tag. Must not be MODE_PLAY. Also updates the
471 * games ply count for the fifty move draw rule.
473 if (d->mode != MODE_PLAY)
474 pgn_board_update (gp, d->b, gp->hindex);
477 static void
478 edit_tag_help (struct menu_input_s *m)
480 message (_("Tag Editing Keys"), ANY_KEY_STR,
481 _(" UP/DOWN - previous/next menu item\n"
482 " HOME/END - first/last menu item\n"
483 " PGDN/PGUP - next/previous page\n"
484 " a-zA-Z0-9 - jump to item\n"
485 " ENTER - edit select item\n"
486 " CTRL-a - add an entry\n"
487 " CTRL-f - add FEN tag from current position\n"
488 " CTRL-r - remove selected entry\n"
489 " CTRL-t - add custom tags\n"
490 " CTRL-x - quit with changes\n"
491 " ESCAPE - quit without changes"));
494 static void
495 view_tag_help (struct menu_input_s *m)
497 message (_("Tag Viewing Keys"), ANY_KEY_STR,
498 _(" UP/DOWN - previous/next menu item\n"
499 " HOME/END - first/last menu item\n"
500 " PGDN/PGUP - next/previous page\n"
501 " a-zA-Z0-9 - jump to item\n"
502 " ENTER - view selected item\n" " ESCAPE - cancel"));
505 static void
506 view_tag_quit (struct menu_input_s *m)
508 pushkey = -1;
511 static void
512 view_tag_value (struct menu_input_s *m)
514 struct menu_item_s *item = m->items[m->selected];
515 char buf[COLS - 4];
516 wchar_t *wc = str_to_wchar (item->name);
518 snprintf (buf, sizeof (buf), "%s \"%ls\"", _("Viewing Tag"), wc);
519 free (wc);
520 construct_message (buf, ANY_KEY_STR, 0, 1, NULL,
521 NULL, NULL, NULL, 0, 0, NULL, "%s", item->value);
524 static void
525 tag_print (WIN * win)
527 int i, len = 0, n;
528 struct menu_input_s *m = win->data;
529 wchar_t *wc;
531 for (i = 0; m->items[i]; i++)
533 wc = translate_tag_name (m->items[i]->name);
534 n = wcslen (wc);
535 free (wc);
536 if (len < n)
537 len = n;
540 wc = translate_tag_name (m->item->name);
541 mvwprintw (win->w, m->print_line, 1, "%ls", wc);
543 for (n = wcslen (wc) + 1; n <= len; n++)
544 mvwprintw (win->w, m->print_line, n, "%c", '.');
546 free (wc);
547 mvwprintw (win->w, m->print_line, n, ": ");
548 i = win->cols - n - 3;
549 wc = str_etc (m->item->value, i, 0);
550 mvwprintw (win->w, m->print_line, n + 2, "%-*ls", i, wc);
551 free (wc);
553 if (m->update)
555 wmove (stdscr, 0, 0);
556 wclrtobot (stdscr);
557 update_all (gp);
558 m->update = 0;
562 void
563 edit_tags (GAME g, BOARD b, int edit)
565 struct menu_key_s **keys = NULL;
566 TAG **data = NULL;
567 int i;
569 if (edit)
571 for (i = 0; gp->tag[i]; i++)
572 pgn_tag_add (&data, gp->tag[i]->name, gp->tag[i]->value);
574 add_menu_key (&keys, '\n', edit_tag_value);
575 add_menu_key (&keys, CTRL_KEY ('f'), edit_tag_add_fen);
576 add_menu_key (&keys, CTRL_KEY ('a'), edit_tag_add);
577 add_menu_key (&keys, CTRL_KEY ('r'), edit_tag_remove);
578 add_menu_key (&keys, CTRL_KEY ('t'), edit_tag_add_custom);
579 add_menu_key (&keys, CTRL_KEY ('x'), edit_tag_save);
580 add_menu_key (&keys, KEY_ESCAPE, edit_tag_abort);
581 add_menu_key (&keys, KEY_F (1), edit_tag_help);
583 else
585 add_menu_key (&keys, '\n', view_tag_value);
586 data = gp->tag;
587 add_menu_key (&keys, KEY_ESCAPE, view_tag_quit);
588 add_menu_key (&keys, KEY_F (1), view_tag_help);
591 construct_menu (0, 0, -1, -1,
592 (edit) ? _("Editing Roster Tags") :
593 _("Viewing Roster Tags"), 0, get_tag_items, keys, data,
594 tag_print, NULL, NULL);