Build fix.
[cboard.git] / src / tags.c
blob789fb9da3c6884cffefb1268a10a5915c7bcb014
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 <string.h>
25 #include <sys/time.h>
26 #include <time.h>
27 #include <limits.h>
28 #include <errno.h>
30 #ifdef HAVE_STRINGS_H
31 #include <strings.h>
32 #endif
34 #include "common.h"
35 #include "conf.h"
36 #include "colors.h"
37 #include "strings.h"
38 #include "window.h"
39 #include "input.h"
40 #include "misc.h"
41 #include "message.h"
42 #include "menu.h"
43 #include "keys.h"
44 #include "tags.h"
46 static int init_country_codes()
48 FILE *fp;
49 char line[LINE_MAX], *s;
50 int cindex = 0;
52 if ((fp = fopen(config.ccfile, "r")) == NULL) {
53 cmessage(ERROR, ANYKEY, "%s: %s", config.ccfile, strerror(errno));
54 return 1;
57 while ((s = fgets(line, sizeof(line), fp)) != NULL) {
58 char *tmp;
60 if ((tmp = strsep(&s, " ")) == NULL)
61 continue;
63 s = trim(s);
64 tmp = trim(tmp);
66 if (!s || !tmp)
67 continue;
69 ccodes = Realloc(ccodes, (cindex + 2) * sizeof(struct country_codes));
70 strncpy(ccodes[cindex].code, tmp, sizeof(ccodes[cindex].code));
71 strncpy(ccodes[cindex].country, s, sizeof(ccodes[cindex].country));
72 cindex++;
75 memset(&ccodes[cindex], '\0', sizeof(struct country_codes));
76 fclose(fp);
77 return 0;
80 static struct menu_item_s **get_cc_items(WIN *win)
82 int i;
83 struct menu_input_s *m = win->data;
84 struct menu_item_s **items = m->items;
86 if (items) {
87 for (i = 0; items[i]; i++)
88 free(items[i]);
91 for (i = 0; ccodes[i].code && ccodes[i].code[0]; i++) {
92 items = Realloc(items, (i+2) * sizeof(struct menu_item_s *));
93 items[i] = Malloc(sizeof(struct menu_item_s));
94 items[i]->name = ccodes[i].code;
95 items[i]->value = ccodes[i].country;
96 items[i]->selected = 0;
99 items[i] = NULL;
100 m->total = i;
101 m->items = items;
102 m->nofree = 1;
103 return items;
106 static void do_cc_help(struct menu_input_s *m)
108 message(CC_KEY_HELP, ANYKEY, "%s", cc_help);
111 static void do_cc_abort(struct menu_input_s *m)
113 pushkey = -1;
116 static void do_cc_finalize(WIN *win)
118 struct input_s *in = win->data;
119 TAG *t = (TAG *)in->arg;
121 set_field_buffer(in->fields[0], 0, t->value);
124 static void do_cc_save(struct menu_input_s *m)
126 struct input_s *in = m->data;
127 TAG *t = (TAG *)in->arg;
128 int len = strlen(m->items[m->selected]->name);
130 t->value = Realloc(t->value, len + 1);
131 strcpy(t->value, m->items[m->selected]->name);
132 pushkey = -1;
135 static void cc_print(WIN *win)
137 struct menu_input_s *m = win->data;
139 mvwprintw(win->w, m->print_line, 1, "%s %-*s", m->item->name,
140 win->cols - 6, m->item->value);
143 static void country_codes(void *arg)
145 struct menu_key_s **keys = NULL;
147 if (!ccodes) {
148 if (init_country_codes())
149 return;
152 add_menu_key(&keys, KEY_F(1), do_cc_help);
153 add_menu_key(&keys, KEY_ESCAPE, do_cc_abort);
154 add_menu_key(&keys, '\n', do_cc_save);
155 construct_menu(0, 0, -1, -1, CC_TITLE, 0, get_cc_items, keys, arg,
156 cc_print, do_cc_finalize);
157 return;
160 void add_custom_tags(TAG ***t)
162 int i;
163 int total = pgn_tag_total(config.tag);
165 if (!config.tag)
166 return;
168 for (i = 0; i < total; i++)
169 pgn_tag_add(t, config.tag[i]->name, config.tag[i]->value);
171 pgn_tag_sort(*t);
174 static struct menu_item_s **get_tag_items(WIN *win)
176 int i, n;
177 struct menu_input_s *m = win->data;
178 struct menu_item_s **items = m->items;
179 TAG **t = (m->data) ? m->data : gp->tag;
181 if (items) {
182 for (i = 0; items[i]; i++)
183 free(items[i]);
186 n = pgn_tag_total(t);
188 for (i = 0; i < n; i++) {
189 items = Realloc(items, (i+2) * sizeof(struct menu_item_s *));
190 items[i] = Malloc(sizeof(struct menu_item_s));
191 items[i]->name = t[i]->name;
192 items[i]->value = t[i]->value;
193 items[i]->selected = 0;
196 items[i] = NULL;
197 m->total = i;
198 m->items = items;
199 m->nofree = 1;
200 return items;
203 static void edit_tag_add_fen(struct menu_input_s *m)
205 TAG **t = m->data;
206 struct userdata_s *d = gp->data;
208 pgn_tag_add(&t, "FEN", pgn_game_to_fen(gp, d->b));
209 m->data = t;
212 static void edit_tag_abort(struct menu_input_s *m)
214 TAG **t = m->data;
216 pgn_tag_free(t);
217 m->data = NULL;
218 pushkey = -1;
219 update_status_notify(gp, "Tag edit aborted.");
222 static void edit_tag_add_finalize(WIN *w)
224 struct input_data_s *in = w->data;
225 char *name = in->moredata;
226 char *value = in->str;
227 struct menu_input_s *m = in->data;
228 TAG **t = m->data;
229 char buf[32];
230 struct tm *tm;
231 time_t now;
232 char *tmp;
233 int count;
235 if (!value || !*value) {
236 if (strcasecmp(name, "Round") == 0)
237 value = "-";
238 else if (strcasecmp(name, "Result") == 0)
239 value = "*";
240 else if (strcasecmp(name, "Date") == 0) {
241 time(&now);
242 tm = localtime(&now);
243 strftime(buf, sizeof(buf), PGN_TIME_FORMAT, tm);
244 value = buf;
246 else
247 value = "?";
250 tmp = trim_multi(value);
251 count = pgn_tag_total(t);
252 pgn_tag_add(&t, name, tmp);
253 free(tmp);
254 m->data = t;
256 if (count != pgn_tag_total(t))
257 m->selected = m->total;
259 if (in->str)
260 free(in->str);
262 free(name);
263 free(in);
264 pushkey = REFRESH_MENU;
267 static void set_menu_stuff(TAG **t, char *name, char **init, int *type,
268 int *lines, input_func **func, int *key, char **eprompt, void **arg)
270 int n;
271 char *p;
273 if ((n = pgn_tag_find(t, name)) != -1) {
274 p = t[n]->value;
275 *init = p;
278 if (strcasecmp(name, "Date") == 0) {
279 *type = FIELD_TYPE_PGN_DATE;
280 *lines = 1;
282 else if (strcasecmp(name, "Site") == 0) {
283 *func = country_codes;
284 *key = CTRL('t');
285 *eprompt = CC_PROMPT;
286 *arg = t[n];
288 else if (strcasecmp(name, "Round") == 0) {
289 *type = FIELD_TYPE_PGN_ROUND;
290 *lines = 1;
292 else if (strcasecmp(name, "Result") == 0) {
293 *type = FIELD_TYPE_PGN_RESULT;
294 *lines = 1;
298 static void edit_tag_value(struct menu_input_s *m)
300 char buf[COLS - 4];
301 struct input_data_s *in = Calloc(1, sizeof(struct input_data_s));
302 char *init = NULL;
303 TAG **t = m->data;
304 char *name;
305 int type = -1;
306 input_func *func = NULL;
307 int key = 0;
308 char *eprompt = NULL;
309 void *arg = NULL;
310 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
312 in->data = m;
313 name = strdup(t[m->selected]->name);
314 in->moredata = name;
315 in->efunc = edit_tag_add_finalize;
316 snprintf(buf, sizeof(buf), "%s \"%s\"", TAG_EDIT_TAG_TITLE, name);
317 set_menu_stuff(t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
318 construct_input(buf, init, lines, 0, eprompt, func, arg, key, in, -1, type);
321 static void edit_tag_add_name_finalize(WIN *w)
323 struct input_data_s *in = w->data;
324 struct input_data_s *inv;
325 struct menu_input_s *m = in->data;
326 TAG **t = m->data;
327 char buf[COLS - 4];
328 char *init = NULL;
329 char *name;
330 int key = 0, type = -1;
331 input_func *func = NULL;
332 char *eprompt = NULL;
333 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
334 void *arg = NULL;
336 if (!in->str)
337 return;
339 name = strdup(in->str);
340 inv = Calloc(1, sizeof(struct input_data_s));
341 inv->efunc = edit_tag_add_finalize;
342 inv->data = in->data;
343 inv->moredata = name;
344 free(in->str);
345 free(in);
346 snprintf(buf, sizeof(buf), "%s \"%s\"", TAG_EDIT_TAG_TITLE, name);
347 set_menu_stuff(t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
348 construct_input(buf, init, lines, 0, eprompt, func, arg, key, inv, -1, type);
351 static void edit_tag_add(struct menu_input_s *m)
353 struct input_data_s *in = Calloc(1, sizeof(struct input_s));
355 in->data = m;
356 in->efunc = edit_tag_add_name_finalize;
357 construct_input(TAG_NEW_TITLE, NULL, 1, 1, NULL, NULL, NULL, 0, in, -1,
358 FIELD_TYPE_PGN_TAG_NAME);
361 static void edit_tag_remove(struct menu_input_s *m)
363 TAG **data = NULL;
364 TAG **t = m->data;
365 int i, n = pgn_tag_total(t);
367 if (m->selected < 7) {
368 cmessage(NULL, ANYKEY, "%s", E_REMOVE_STR);
369 return;
372 for (i = 0; i < n; i++) {
373 if (i == m->selected)
374 continue;
376 pgn_tag_add(&data, t[i]->name, t[i]->value);
379 pgn_tag_free(t);
380 m->data = data;
381 m->update = 1;
384 static void edit_tag_add_custom(struct menu_input_s *m)
386 TAG **t = m->data;
388 add_custom_tags(&t);
389 m->data = t;
392 static void edit_tag_save(struct menu_input_s *m)
394 TAG **t = m->data;
395 struct userdata_s *d = gp->data;
397 if (!m->data)
398 return;
400 pgn_tag_free(gp->tag);
401 pgn_tag_sort(t);
402 gp->tag = t;
403 pushkey = -1;
404 SET_FLAG(d->flags, CF_MODIFIED);
407 * In case of editing a FEN tag. Must not be MODE_PLAY. Also updates the
408 * games ply count for the fifty move draw rule.
410 if (d->mode != MODE_PLAY)
411 pgn_board_update(gp, d->b, gp->hindex);
414 static void edit_tag_help(struct menu_input_s *m)
416 message(TAG_EDIT_HELP, ANYKEY, edit_help);
419 static void view_tag_help(struct menu_input_s *m)
421 message(TAG_VIEW_HELP, ANYKEY, view_help);
424 static void view_tag_quit(struct menu_input_s *m)
426 pushkey = -1;
429 static void view_tag_value(struct menu_input_s *m)
431 struct menu_item_s *item = m->items[m->selected];
432 char buf[COLS - 4];
434 snprintf(buf, sizeof(buf), "%s \"%s\"", TAG_VIEW_TAG_TITLE, item->name);
435 construct_message(buf, ANYKEY, 0, 1, NULL, NULL, NULL, NULL, 0, 0, item->value);
438 static void tag_print(WIN *win)
440 int i, len = 0, n;
441 struct menu_input_s *m = win->data;
443 for (i = 0; m->items[i]; i++) {
444 n = strlen(m->items[i]->name);
446 if (len < n)
447 len = n;
450 mvwprintw(win->w, m->print_line, 1, "%s", m->item->name);
452 for (n = strlen(m->item->name) + 1; n <= len; n++)
453 mvwprintw(win->w, m->print_line, n, "%c", '.');
455 mvwprintw(win->w, m->print_line, n, ": ");
456 i = win->cols - n - 2;
457 mvwprintw(win->w, m->print_line, n + 2, "%-*s", i - 1, str_etc(m->item->value, i, 0));
459 if (m->update) {
460 wmove(stdscr, 0, 0);
461 wclrtobot(stdscr);
462 update_all(gp);
463 m->update = 0;
467 void edit_tags(GAME g, BOARD b, int edit)
469 struct menu_key_s **keys = NULL;
470 TAG **data = NULL;
471 int i;
473 if (edit) {
474 for (i = 0; gp->tag[i]; i++)
475 pgn_tag_add(&data, gp->tag[i]->name,
476 gp->tag[i]->value);
478 add_menu_key(&keys, '\n', edit_tag_value);
479 add_menu_key(&keys, CTRL('f'), edit_tag_add_fen);
480 add_menu_key(&keys, CTRL('a'), edit_tag_add);
481 add_menu_key(&keys, CTRL('r'), edit_tag_remove);
482 add_menu_key(&keys, CTRL('t'), edit_tag_add_custom);
483 add_menu_key(&keys, CTRL('x'), edit_tag_save);
484 add_menu_key(&keys, KEY_ESCAPE, edit_tag_abort);
485 add_menu_key(&keys, KEY_F(1), edit_tag_help);
487 else {
488 add_menu_key(&keys, '\n', view_tag_value);
489 data = gp->tag;
490 add_menu_key(&keys, KEY_ESCAPE, view_tag_quit);
491 add_menu_key(&keys, KEY_F(1), view_tag_help);
494 construct_menu(0, 0, -1, -1, (edit) ? TAG_EDIT_TITLE : TAG_VIEW_TITLE, 0,
495 get_tag_items, keys, data, tag_print, NULL);