Autotools portability fixes and cleanups.
[cboard.git] / src / tags.c
blob3b29c9bdf7b961206a1fffbc73df40848b6157ad
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2011 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_NCURSES_H
31 #include <ncurses.h>
32 #elif defined(HAVE_CURSES_H)
33 #include <curses.h>
34 #endif
36 #ifdef HAVE_PANEL_H
37 #include <panel.h>
38 #endif
40 #ifdef HAVE_STRINGS_H
41 #include <strings.h>
42 #endif
44 #include "chess.h"
45 #include "common.h"
46 #include "conf.h"
47 #include "colors.h"
48 #include "strings.h"
49 #include "window.h"
50 #include "input.h"
51 #include "misc.h"
52 #include "message.h"
53 #include "menu.h"
54 #include "keys.h"
55 #include "tags.h"
57 static int init_country_codes()
59 FILE *fp;
60 char line[LINE_MAX], *s;
61 int cindex = 0;
63 if ((fp = fopen(config.ccfile, "r")) == NULL) {
64 cmessage(ERROR, ANYKEY, "%s: %s", config.ccfile, strerror(errno));
65 return 1;
68 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 strncpy(ccodes[cindex].country, s, sizeof(ccodes[cindex].country));
83 cindex++;
86 memset(&ccodes[cindex], '\0', sizeof(struct country_codes));
87 fclose(fp);
88 return 0;
91 static struct menu_item_s **get_cc_items(WIN *win)
93 int i;
94 struct menu_input_s *m = win->data;
95 struct menu_item_s **items = m->items;
97 if (items) {
98 for (i = 0; items[i]; i++)
99 free(items[i]);
102 for (i = 0; ccodes[i].code && ccodes[i].code[0]; i++) {
103 items = Realloc(items, (i+2) * sizeof(struct menu_item_s *));
104 items[i] = Malloc(sizeof(struct menu_item_s));
105 items[i]->name = ccodes[i].code;
106 items[i]->value = ccodes[i].country;
107 items[i]->selected = 0;
110 items[i] = NULL;
111 m->total = i;
112 m->items = items;
113 m->nofree = 1;
114 return items;
117 static void do_cc_help(struct menu_input_s *m)
119 message(CC_KEY_HELP, ANYKEY, "%s", cc_help);
122 static void do_cc_abort(struct menu_input_s *m)
124 pushkey = -1;
127 static void do_cc_finalize(WIN *win)
129 struct input_s *in = win->data;
130 TAG *t = (TAG *)in->arg;
132 set_field_buffer(in->fields[0], 0, t->value);
135 static void do_cc_save(struct menu_input_s *m)
137 struct input_s *in = m->data;
138 TAG *t = (TAG *)in->arg;
139 int len = strlen(m->items[m->selected]->name);
141 t->value = Realloc(t->value, len + 1);
142 strcpy(t->value, m->items[m->selected]->name);
143 pushkey = -1;
146 static void cc_print(WIN *win)
148 struct menu_input_s *m = win->data;
150 mvwprintw(win->w, m->print_line, 1, "%s %-*s", m->item->name,
151 win->cols - 6, m->item->value);
154 static void country_codes(void *arg)
156 struct menu_key_s **keys = NULL;
158 if (!ccodes) {
159 if (init_country_codes())
160 return;
163 add_menu_key(&keys, KEY_F(1), do_cc_help);
164 add_menu_key(&keys, KEY_ESCAPE, do_cc_abort);
165 add_menu_key(&keys, '\n', do_cc_save);
166 construct_menu(0, 0, -1, -1, CC_TITLE, 0, get_cc_items, keys, arg,
167 cc_print, do_cc_finalize);
168 return;
171 void add_custom_tags(TAG ***t)
173 int i;
174 int total = pgn_tag_total(config.tag);
176 if (!config.tag)
177 return;
179 for (i = 0; i < total; i++)
180 pgn_tag_add(t, config.tag[i]->name, config.tag[i]->value);
182 pgn_tag_sort(*t);
185 static struct menu_item_s **get_tag_items(WIN *win)
187 int i, n;
188 struct menu_input_s *m = win->data;
189 struct menu_item_s **items = m->items;
190 TAG **t = (m->data) ? m->data : gp->tag;
192 if (items) {
193 for (i = 0; items[i]; i++)
194 free(items[i]);
197 n = pgn_tag_total(t);
199 for (i = 0; i < n; i++) {
200 items = Realloc(items, (i+2) * sizeof(struct menu_item_s *));
201 items[i] = Malloc(sizeof(struct menu_item_s));
202 items[i]->name = t[i]->name;
203 items[i]->value = t[i]->value;
204 items[i]->selected = 0;
207 items[i] = NULL;
208 m->total = i;
209 m->items = items;
210 m->nofree = 1;
211 return items;
214 static void edit_tag_add_fen(struct menu_input_s *m)
216 TAG **t = m->data;
217 struct userdata_s *d = gp->data;
219 pgn_tag_add(&t, "FEN", pgn_game_to_fen(gp, d->b));
220 m->data = t;
223 static void edit_tag_abort(struct menu_input_s *m)
225 TAG **t = m->data;
227 pgn_tag_free(t);
228 m->data = NULL;
229 pushkey = -1;
230 update_status_notify(gp, "Tag edit aborted.");
233 static void edit_tag_add_finalize(WIN *w)
235 struct input_data_s *in = w->data;
236 char *name = in->moredata;
237 char *value = in->str;
238 struct menu_input_s *m = in->data;
239 TAG **t = m->data;
240 char buf[32];
241 struct tm *tm;
242 time_t now;
243 char *tmp;
244 int count;
246 if (!value || !*value) {
247 if (strcasecmp(name, "Round") == 0)
248 value = "-";
249 else if (strcasecmp(name, "Result") == 0)
250 value = "*";
251 else if (strcasecmp(name, "Date") == 0) {
252 time(&now);
253 tm = localtime(&now);
254 strftime(buf, sizeof(buf), PGN_TIME_FORMAT, tm);
255 value = buf;
257 else
258 value = "?";
261 tmp = trim_multi(value);
262 count = pgn_tag_total(t);
263 pgn_tag_add(&t, name, tmp);
264 free(tmp);
265 m->data = t;
267 if (count != pgn_tag_total(t))
268 m->selected = m->total;
270 if (in->str)
271 free(in->str);
273 free(name);
274 free(in);
275 pushkey = REFRESH_MENU;
278 static void set_menu_stuff(TAG **t, char *name, char **init, int *type,
279 int *lines, input_func **func, int *key, char **eprompt, void **arg)
281 int n;
282 char *p;
284 if ((n = pgn_tag_find(t, name)) != -1) {
285 p = t[n]->value;
286 *init = p;
289 if (strcasecmp(name, "Date") == 0) {
290 *type = FIELD_TYPE_PGN_DATE;
291 *lines = 1;
293 else if (strcasecmp(name, "Site") == 0) {
294 *func = country_codes;
295 *key = CTRL('t');
296 *eprompt = CC_PROMPT;
297 *arg = t[n];
299 else if (strcasecmp(name, "Round") == 0) {
300 *type = FIELD_TYPE_PGN_ROUND;
301 *lines = 1;
303 else if (strcasecmp(name, "Result") == 0) {
304 *type = FIELD_TYPE_PGN_RESULT;
305 *lines = 1;
309 static void edit_tag_value(struct menu_input_s *m)
311 char buf[COLS - 4];
312 struct input_data_s *in = Calloc(1, sizeof(struct input_data_s));
313 char *init = NULL;
314 TAG **t = m->data;
315 char *name;
316 int type = -1;
317 input_func *func = NULL;
318 int key = 0;
319 char *eprompt = NULL;
320 void *arg = NULL;
321 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
323 in->data = m;
324 name = strdup(t[m->selected]->name);
325 in->moredata = name;
326 in->efunc = edit_tag_add_finalize;
327 snprintf(buf, sizeof(buf), "%s \"%s\"", TAG_EDIT_TAG_TITLE, name);
328 set_menu_stuff(t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
329 construct_input(buf, init, lines, 0, eprompt, func, arg, key, in, -1, type);
332 static void edit_tag_add_name_finalize(WIN *w)
334 struct input_data_s *in = w->data;
335 struct input_data_s *inv;
336 struct menu_input_s *m = in->data;
337 TAG **t = m->data;
338 char buf[COLS - 4];
339 char *init = NULL;
340 char *name;
341 int key = 0, type = -1;
342 input_func *func = NULL;
343 char *eprompt = NULL;
344 int lines = MAX_PGN_LINE_LEN / INPUT_WIDTH;
345 void *arg = NULL;
347 if (!in->str)
348 return;
350 name = strdup(in->str);
351 inv = Calloc(1, sizeof(struct input_data_s));
352 inv->efunc = edit_tag_add_finalize;
353 inv->data = in->data;
354 inv->moredata = name;
355 free(in->str);
356 free(in);
357 snprintf(buf, sizeof(buf), "%s \"%s\"", TAG_EDIT_TAG_TITLE, name);
358 set_menu_stuff(t, name, &init, &type, &lines, &func, &key, &eprompt, &arg);
359 construct_input(buf, init, lines, 0, eprompt, func, arg, key, inv, -1, type);
362 static void edit_tag_add(struct menu_input_s *m)
364 struct input_data_s *in = Calloc(1, sizeof(struct input_s));
366 in->data = m;
367 in->efunc = edit_tag_add_name_finalize;
368 construct_input(TAG_NEW_TITLE, NULL, 1, 1, NULL, NULL, NULL, 0, in, -1,
369 FIELD_TYPE_PGN_TAG_NAME);
372 static void edit_tag_remove(struct menu_input_s *m)
374 TAG **data = NULL;
375 TAG **t = m->data;
376 int i, n = pgn_tag_total(t);
378 if (m->selected < 7) {
379 cmessage(NULL, ANYKEY, "%s", E_REMOVE_STR);
380 return;
383 for (i = 0; i < n; i++) {
384 if (i == m->selected)
385 continue;
387 pgn_tag_add(&data, t[i]->name, t[i]->value);
390 pgn_tag_free(t);
391 m->data = data;
392 m->update = 1;
395 static void edit_tag_add_custom(struct menu_input_s *m)
397 TAG **t = m->data;
399 add_custom_tags(&t);
400 m->data = t;
403 static void edit_tag_save(struct menu_input_s *m)
405 TAG **t = m->data;
406 struct userdata_s *d = gp->data;
408 if (!m->data)
409 return;
411 pgn_tag_free(gp->tag);
412 pgn_tag_sort(t);
413 gp->tag = t;
414 pushkey = -1;
415 SET_FLAG(d->flags, CF_MODIFIED);
418 * In case of editing a FEN tag. Must not be MODE_PLAY. Also updates the
419 * games ply count for the fifty move draw rule.
421 if (d->mode != MODE_PLAY)
422 pgn_board_update(gp, d->b, gp->hindex);
425 static void edit_tag_help(struct menu_input_s *m)
427 message(TAG_EDIT_HELP, ANYKEY, edit_help);
430 static void view_tag_help(struct menu_input_s *m)
432 message(TAG_VIEW_HELP, ANYKEY, view_help);
435 static void view_tag_quit(struct menu_input_s *m)
437 pushkey = -1;
440 static void view_tag_value(struct menu_input_s *m)
442 struct menu_item_s *item = m->items[m->selected];
443 char buf[COLS - 4];
445 snprintf(buf, sizeof(buf), "%s \"%s\"", TAG_VIEW_TAG_TITLE, item->name);
446 construct_message(buf, ANYKEY, 0, 1, NULL, NULL, NULL, NULL, 0, 0, item->value);
449 static void tag_print(WIN *win)
451 int i, len = 0, n;
452 struct menu_input_s *m = win->data;
454 for (i = 0; m->items[i]; i++) {
455 n = strlen(m->items[i]->name);
457 if (len < n)
458 len = n;
461 mvwprintw(win->w, m->print_line, 1, "%s", m->item->name);
463 for (n = strlen(m->item->name) + 1; n <= len; n++)
464 mvwprintw(win->w, m->print_line, n, "%c", '.');
466 mvwprintw(win->w, m->print_line, n, ": ");
467 i = win->cols - n - 2;
468 mvwprintw(win->w, m->print_line, n + 2, "%-*s", i - 1, str_etc(m->item->value, i, 0));
470 if (m->update) {
471 wmove(stdscr, 0, 0);
472 wclrtobot(stdscr);
473 update_all(gp);
474 m->update = 0;
478 void edit_tags(GAME g, BOARD b, int edit)
480 struct menu_key_s **keys = NULL;
481 TAG **data = NULL;
482 int i;
484 if (edit) {
485 for (i = 0; gp->tag[i]; i++)
486 pgn_tag_add(&data, gp->tag[i]->name,
487 gp->tag[i]->value);
489 add_menu_key(&keys, '\n', edit_tag_value);
490 add_menu_key(&keys, CTRL('f'), edit_tag_add_fen);
491 add_menu_key(&keys, CTRL('a'), edit_tag_add);
492 add_menu_key(&keys, CTRL('r'), edit_tag_remove);
493 add_menu_key(&keys, CTRL('t'), edit_tag_add_custom);
494 add_menu_key(&keys, CTRL('x'), edit_tag_save);
495 add_menu_key(&keys, KEY_ESCAPE, edit_tag_abort);
496 add_menu_key(&keys, KEY_F(1), edit_tag_help);
498 else {
499 add_menu_key(&keys, '\n', view_tag_value);
500 data = gp->tag;
501 add_menu_key(&keys, KEY_ESCAPE, view_tag_quit);
502 add_menu_key(&keys, KEY_F(1), view_tag_help);
505 construct_menu(0, 0, -1, -1, (edit) ? TAG_EDIT_TITLE : TAG_VIEW_TITLE, 0,
506 get_tag_items, keys, data, tag_print, NULL);