Makefile fixup.
[cboard.git] / src / tags.c
blob8fcb89a679b5ac77eaf20f2655025aa4904627c1
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2013 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 {
47 char code[4];
48 char country[64];
49 } *ccodes;
51 static int init_country_codes()
53 FILE *fp;
54 char line[LINE_MAX], *s;
55 int cindex = 0;
57 if ((fp = fopen(config.ccfile, "r")) == NULL) {
58 cmessage(_("[ ERROR ]"), _("[ press any key to continue ]"), "%s: %s", config.ccfile, strerror(errno));
59 return 1;
62 while ((s = fgets(line, sizeof(line), fp)) != NULL) {
63 char *tmp;
65 if ((tmp = strsep(&s, " ")) == NULL)
66 continue;
68 s = trim(s);
69 tmp = trim(tmp);
71 if (!s || !tmp)
72 continue;
74 ccodes = Realloc(ccodes, (cindex + 2) * sizeof(struct country_codes));
75 strncpy(ccodes[cindex].code, tmp, sizeof(ccodes[cindex].code));
76 strncpy(ccodes[cindex].country, s, sizeof(ccodes[cindex].country));
77 cindex++;
80 memset(&ccodes[cindex], '\0', sizeof(struct country_codes));
81 fclose(fp);
82 return 0;
85 static struct menu_item_s **get_cc_items(WIN *win)
87 int i;
88 struct menu_input_s *m = win->data;
89 struct menu_item_s **items = m->items;
91 if (items) {
92 for (i = 0; items[i]; i++)
93 free(items[i]);
96 for (i = 0; ccodes[i].code && ccodes[i].code[0]; i++) {
97 items = Realloc(items, (i+2) * sizeof(struct menu_item_s *));
98 items[i] = Malloc(sizeof(struct menu_item_s));
99 items[i]->name = ccodes[i].code;
100 items[i]->value = ccodes[i].country;
101 items[i]->selected = 0;
104 items[i] = NULL;
105 m->total = i;
106 m->items = items;
107 m->nofree = 1;
108 return items;
111 static void do_cc_help(struct menu_input_s *m)
113 message(_("Country Code Keys"), _("[ press any key to continue ]"), "%s",
115 " UP/DOWN - previous/next menu item\n"
116 " HOME/END - first/last menu item\n"
117 " PGDN/PGUP - next/previous page\n"
118 " a-zA-Z0-9 - jump to item\n"
119 " ENTER - select item\n"
120 " ESCAPE - cancel"
124 static void do_cc_abort(struct menu_input_s *m)
126 pushkey = -1;
129 static void do_cc_finalize(WIN *win)
131 struct input_s *in = win->data;
132 TAG *t = (TAG *)in->arg;
134 set_field_buffer(in->fields[0], 0, t->value);
137 static void do_cc_save(struct menu_input_s *m)
139 struct input_s *in = m->data;
140 TAG *t = (TAG *)in->arg;
141 int len = strlen(m->items[m->selected]->name);
143 t->value = Realloc(t->value, len + 1);
144 strcpy(t->value, m->items[m->selected]->name);
145 pushkey = -1;
148 static void cc_print(WIN *win)
150 struct menu_input_s *m = win->data;
152 mvwprintw(win->w, m->print_line, 1, "%s %-*s", m->item->name,
153 win->cols - 6, m->item->value);
156 static void country_codes(void *arg)
158 struct menu_key_s **keys = NULL;
160 if (!ccodes) {
161 if (init_country_codes())
162 return;
165 add_menu_key(&keys, KEY_F(1), do_cc_help);
166 add_menu_key(&keys, KEY_ESCAPE, do_cc_abort);
167 add_menu_key(&keys, '\n', do_cc_save);
168 construct_menu(0, 0, -1, -1, _("Country Codes"), 0, get_cc_items, keys, arg,
169 cc_print, do_cc_finalize);
170 return;
173 void add_custom_tags(TAG ***t)
175 int i;
176 int total = pgn_tag_total(config.tag);
178 if (!config.tag)
179 return;
181 for (i = 0; i < total; i++)
182 pgn_tag_add(t, config.tag[i]->name, config.tag[i]->value);
184 pgn_tag_sort(*t);
187 static struct menu_item_s **get_tag_items(WIN *win)
189 int i, n;
190 struct menu_input_s *m = win->data;
191 struct menu_item_s **items = m->items;
192 TAG **t = (m->data) ? m->data : gp->tag;
194 if (items) {
195 for (i = 0; items[i]; i++)
196 free(items[i]);
199 n = pgn_tag_total(t);
201 for (i = 0; i < n; i++) {
202 items = Realloc(items, (i+2) * sizeof(struct menu_item_s *));
203 items[i] = Malloc(sizeof(struct menu_item_s));
204 items[i]->name = t[i]->name;
205 items[i]->value = t[i]->value;
206 items[i]->selected = 0;
209 items[i] = NULL;
210 m->total = i;
211 m->items = items;
212 m->nofree = 1;
213 return items;
216 static void edit_tag_add_fen(struct menu_input_s *m)
218 TAG **t = m->data;
219 struct userdata_s *d = gp->data;
220 char *fen = pgn_game_to_fen(gp, d->b);
222 pgn_tag_add(&t, "FEN", fen);
223 free (fen);
224 m->data = t;
227 static void edit_tag_abort(struct menu_input_s *m)
229 TAG **t = m->data;
231 pgn_tag_free(t);
232 m->data = NULL;
233 pushkey = -1;
234 update_status_notify(gp, "Tag edit aborted.");
237 static void edit_tag_add_finalize(WIN *w)
239 struct input_data_s *in = w->data;
240 char *name = in->moredata;
241 char *value = in->str;
242 struct menu_input_s *m = in->data;
243 TAG **t = m->data;
244 char buf[32];
245 struct tm *tm;
246 time_t now;
247 char *tmp;
248 int count;
250 if (!value || !*value) {
251 if (strcasecmp(name, "Round") == 0)
252 value = "-";
253 else if (strcasecmp(name, "Result") == 0)
254 value = "*";
255 else if (strcasecmp(name, "Date") == 0) {
256 time(&now);
257 tm = localtime(&now);
258 strftime(buf, sizeof(buf), PGN_TIME_FORMAT, tm);
259 value = buf;
261 else
262 value = "?";
265 tmp = trim_multi(value);
266 count = pgn_tag_total(t);
267 pgn_tag_add(&t, name, tmp);
268 free(tmp);
269 m->data = t;
271 if (count != pgn_tag_total(t))
272 m->selected = m->total;
274 if (in->str)
275 free(in->str);
277 free(name);
278 free(in);
279 pushkey = REFRESH_MENU;
282 static void set_menu_stuff(TAG **t, char *name, char **init, int *type,
283 int *lines, input_func **func, int *key, char **eprompt, void **arg)
285 int n;
286 char *p;
288 if ((n = pgn_tag_find(t, name)) != -1) {
289 p = t[n]->value;
290 *init = p;
293 if (strcasecmp(name, "Date") == 0) {
294 *type = FIELD_TYPE_PGN_DATE;
295 *lines = 1;
297 else if (strcasecmp(name, "Site") == 0) {
298 *func = country_codes;
299 *key = CTRL_KEY('t');
300 *eprompt = _("Type CTRL-t for country codes");
301 *arg = t[n];
303 else if (strcasecmp(name, "Round") == 0) {
304 *type = FIELD_TYPE_PGN_ROUND;
305 *lines = 1;
307 else if (strcasecmp(name, "Result") == 0) {
308 *type = FIELD_TYPE_PGN_RESULT;
309 *lines = 1;
313 static void edit_tag_value(struct menu_input_s *m)
315 char buf[COLS - 4];
316 struct input_data_s *in = Calloc(1, sizeof(struct input_data_s));
317 char *init = NULL;
318 TAG **t = m->data;
319 char *name;
320 int type = -1;
321 input_func *func = NULL;
322 int key = 0;
323 char *eprompt = NULL;
324 void *arg = NULL;
325 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
327 in->data = m;
328 name = strdup(t[m->selected]->name);
329 in->moredata = name;
330 in->efunc = edit_tag_add_finalize;
331 snprintf(buf, sizeof(buf), "%s \"%s\"", _("Editing Tag"), name);
332 set_menu_stuff(t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
333 construct_input(buf, init, lines, 0, eprompt, func, arg, key, in, -1, type);
336 static void edit_tag_add_name_finalize(WIN *w)
338 struct input_data_s *in = w->data;
339 struct input_data_s *inv;
340 struct menu_input_s *m = in->data;
341 TAG **t = m->data;
342 char buf[COLS - 4];
343 char *init = NULL;
344 char *name;
345 int key = 0, type = -1;
346 input_func *func = NULL;
347 char *eprompt = NULL;
348 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
349 void *arg = NULL;
351 if (!in->str)
352 return;
354 name = strdup(in->str);
355 inv = Calloc(1, sizeof(struct input_data_s));
356 inv->efunc = edit_tag_add_finalize;
357 inv->data = in->data;
358 inv->moredata = name;
359 free(in->str);
360 free(in);
361 snprintf(buf, sizeof(buf), "%s \"%s\"", _("Editing Tag"), name);
362 set_menu_stuff(t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
363 construct_input(buf, init, lines, 0, eprompt, func, arg, key, inv, -1, type);
366 static void edit_tag_add(struct menu_input_s *m)
368 struct input_data_s *in = Calloc(1, sizeof(struct input_s));
370 in->data = m;
371 in->efunc = edit_tag_add_name_finalize;
372 construct_input(_("New Tag Name"), NULL, 1, 1, NULL, NULL, NULL, 0, in, -1,
373 FIELD_TYPE_PGN_TAG_NAME);
376 static void edit_tag_remove(struct menu_input_s *m)
378 TAG **data = NULL;
379 TAG **t = m->data;
380 int i, n = pgn_tag_total(t);
382 if (m->selected < 7) {
383 cmessage(NULL, _("[ press any key to continue ]"), "%s", _ ("Cannot remove the Seven Tag Roster"));
384 return;
387 for (i = 0; i < n; i++) {
388 if (i == m->selected)
389 continue;
391 pgn_tag_add(&data, t[i]->name, t[i]->value);
394 pgn_tag_free(t);
395 m->data = data;
396 m->update = 1;
399 static void edit_tag_add_custom(struct menu_input_s *m)
401 TAG **t = m->data;
403 add_custom_tags(&t);
404 m->data = t;
407 static void edit_tag_save(struct menu_input_s *m)
409 TAG **t = m->data;
410 struct userdata_s *d = gp->data;
412 if (!m->data)
413 return;
415 pgn_tag_free(gp->tag);
416 pgn_tag_sort(t);
417 gp->tag = t;
418 pushkey = -1;
419 SET_FLAG(d->flags, CF_MODIFIED);
422 * In case of editing a FEN tag. Must not be MODE_PLAY. Also updates the
423 * games ply count for the fifty move draw rule.
425 if (d->mode != MODE_PLAY)
426 pgn_board_update(gp, d->b, gp->hindex);
429 static void edit_tag_help(struct menu_input_s *m)
431 message(_("Tag Editing Keys"), _("[ press any key to continue ]"),
433 " UP/DOWN - previous/next menu item\n"
434 " HOME/END - first/last menu item\n"
435 " PGDN/PGUP - next/previous page\n"
436 " a-zA-Z0-9 - jump to item\n"
437 " ENTER - edit select item\n"
438 " CTRL-a - add an entry\n"
439 " CTRL-f - add FEN tag from current position\n"
440 " CTRL-r - remove selected entry\n"
441 " CTRL-t - add custom tags\n"
442 " CTRL-x - quit with changes\n"
443 " ESCAPE - quit without changes"
447 static void view_tag_help(struct menu_input_s *m)
449 message(_("Tag Viewing Keys"), _("[ press any key to continue ]"),
451 " UP/DOWN - previous/next menu item\n"
452 " HOME/END - first/last menu item\n"
453 " PGDN/PGUP - next/previous page\n"
454 " a-zA-Z0-9 - jump to item\n"
455 " ENTER - view selected item\n"
456 " ESCAPE - cancel"
460 static void view_tag_quit(struct menu_input_s *m)
462 pushkey = -1;
465 static void view_tag_value(struct menu_input_s *m)
467 struct menu_item_s *item = m->items[m->selected];
468 char buf[COLS - 4];
470 snprintf(buf, sizeof(buf), "%s \"%s\"", _("Viewing Tag"), item->name);
471 construct_message(buf, _("[ press any key to continue ]"), 0, 1, NULL, NULL, NULL, NULL, 0, 0, item->value);
474 static void tag_print(WIN *win)
476 int i, len = 0, n;
477 struct menu_input_s *m = win->data;
479 for (i = 0; m->items[i]; i++) {
480 n = strlen(m->items[i]->name);
482 if (len < n)
483 len = n;
486 mvwprintw(win->w, m->print_line, 1, "%s", m->item->name);
488 for (n = strlen(m->item->name) + 1; n <= len; n++)
489 mvwprintw(win->w, m->print_line, n, "%c", '.');
491 mvwprintw(win->w, m->print_line, n, ": ");
492 i = win->cols - n - 2;
493 mvwprintw(win->w, m->print_line, n + 2, "%-*s", i - 1, str_etc(m->item->value, i, 0));
495 if (m->update) {
496 wmove(stdscr, 0, 0);
497 wclrtobot(stdscr);
498 update_all(gp);
499 m->update = 0;
503 void edit_tags(GAME g, BOARD b, int edit)
505 struct menu_key_s **keys = NULL;
506 TAG **data = NULL;
507 int i;
509 if (edit) {
510 for (i = 0; gp->tag[i]; i++)
511 pgn_tag_add(&data, gp->tag[i]->name, gp->tag[i]->value);
513 add_menu_key(&keys, '\n', edit_tag_value);
514 add_menu_key(&keys, CTRL_KEY('f'), edit_tag_add_fen);
515 add_menu_key(&keys, CTRL_KEY('a'), edit_tag_add);
516 add_menu_key(&keys, CTRL_KEY('r'), edit_tag_remove);
517 add_menu_key(&keys, CTRL_KEY('t'), edit_tag_add_custom);
518 add_menu_key(&keys, CTRL_KEY('x'), edit_tag_save);
519 add_menu_key(&keys, KEY_ESCAPE, edit_tag_abort);
520 add_menu_key(&keys, KEY_F(1), edit_tag_help);
522 else {
523 add_menu_key(&keys, '\n', view_tag_value);
524 data = gp->tag;
525 add_menu_key(&keys, KEY_ESCAPE, view_tag_quit);
526 add_menu_key(&keys, KEY_F(1), view_tag_help);
529 construct_menu(0, 0, -1, -1, (edit) ? _("Editing Roster Tags") : _("Viewing Roster Tags"),
530 0, get_tag_items, keys, data, tag_print, NULL);