things to do before the next merge
[cboard.git] / src / rcfile.c
blobb85d3093a1e5ad30d38de80ddc6d69b380c5f850
1 /* $Id: rcfile.c,v 1.29 2003-02-07 19:44:30 bjk Exp $ */
2 /*
3 Copyright (C) 2002-2003 Ben Kibbey <bjk@arbornet.org>
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 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <err.h>
23 #include <ctype.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <errno.h>
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
32 #include "common.h"
33 #include "rcfile.h"
35 static int attributes(const char *filename, int line, char *str)
37 char *tmp;
38 int attrs = 0;
40 while ((tmp = strsep(&str, ",")) != NULL) {
41 if (strcasecmp(tmp, "BOLD") == 0)
42 attrs |= A_BOLD;
43 else if (strcasecmp(tmp, "REVERSE") == 0)
44 attrs |= A_REVERSE;
45 else if (strcasecmp(tmp, "NONE") == 0)
46 attrs |= A_NORMAL;
47 else if (strcasecmp(tmp, "DIM") == 0)
48 attrs |= A_DIM;
49 else if (strcasecmp(tmp, "STANDOUT") == 0)
50 attrs |= A_STANDOUT;
51 else if (strcasecmp(tmp, "UNDERLINE") == 0)
52 attrs |= A_UNDERLINE;
53 else if (strcasecmp(tmp, "BLINK") == 0)
54 attrs |= A_BLINK;
55 else if (strcasecmp(tmp, "INVISIBLE") == 0)
56 attrs |= A_INVIS;
57 else
58 errx(EXIT_FAILURE, "%s(%i): invalid attribute \"%s\"", filename,
59 line, tmp);
62 return attrs;
65 static short color_name(const char *filename, int line, const char *color)
67 if (strcasecmp(color, "BLACK") == 0)
68 return COLOR_BLACK;
69 else if (strcasecmp(color, "WHITE") == 0)
70 return COLOR_WHITE;
71 else if (strcasecmp(color, "GREEN") == 0)
72 return COLOR_GREEN;
73 else if (strcasecmp(color, "YELLOW") == 0)
74 return COLOR_YELLOW;
75 else if (strcasecmp(color, "MAGENTA") == 0)
76 return COLOR_MAGENTA;
77 else if (strcasecmp(color, "BLUE") == 0)
78 return COLOR_BLUE;
79 else if (strcasecmp(color, "RED") == 0)
80 return COLOR_RED;
81 else if (strcasecmp(color, "CYAN") == 0)
82 return COLOR_CYAN;
83 else
84 errx(EXIT_FAILURE, "%s(%i): invalid color \"%s\"", filename, line,
85 color);
87 return -1;
90 static void parse_color(const char *filename, int line, const char *str,
91 struct colors *c)
93 char fg[16], bg[16], attr[64], nattr[64];
94 struct colors ctmp = *c;
95 int n;
97 if ((n = sscanf(str, "%[a-zA-Z] %[a-zA-Z] %[a-zA-Z,] %[a-zA-Z,]", fg, bg,
98 attr, nattr)) < 2)
99 errx(EXIT_FAILURE, "%s(%i): parse error", filename, line);
101 ctmp.fg = color_name(filename, line, fg);
102 ctmp.bg = color_name(filename, line, bg);
103 ctmp.attrs = ctmp.nattrs = 0;
105 if (n > 2)
106 ctmp.attrs = attributes(filename, line, attr);
108 if (n > 3)
109 ctmp.nattrs = attributes(filename, line, nattr);
111 *c = ctmp;
112 return;
115 static int on_or_off(const char *filename, int lines, const char *str)
117 if (strcmp(str, "on") == 0)
118 return 1;
120 if (strcmp(str, "off") == 0)
121 return 0;
123 errx(EXIT_FAILURE, "%s(%i): invalid value \"%s\"", filename, lines, str);
126 void copydatafile(const char *dst, const char *src)
128 FILE *fp, *ofp;
129 char buf[LINE_MAX], *s;
131 snprintf(buf, sizeof(buf), "%s/%s", DATA_PATH, src);
133 fprintf(stderr, "%s %s...\n", COPY_DATAFILE, buf);
135 if ((fp = fopen(buf, "r")) == NULL) {
136 warn("%s", buf);
137 return;
140 if ((ofp = fopen(dst, "w+")) == NULL) {
141 fclose(fp);
142 warn("%s", dst);
143 return;
146 while ((s = fgets(buf, sizeof(buf), fp)) != NULL)
147 fprintf(ofp, "%s", s);
149 fclose(fp);
150 fclose(ofp);
151 return;
154 void set_defaults()
156 struct stat st;
158 status.mode = MODE_PLAY;
159 filetype = PGN_FILE;
161 fancy_results[0].pgn = "1-0";
162 fancy_results[1].pgn = "0-1";
163 fancy_results[2].pgn = "1/2-1/2";
164 fancy_results[3].pgn = "*";
165 fancy_results[0].fancy = TAG_RESULT_FANCY_WHITE;
166 fancy_results[1].fancy = TAG_RESULT_FANCY_BLACK;
167 fancy_results[2].fancy = TAG_RESULT_FANCY_DRAW;
168 fancy_results[3].fancy = TAG_RESULT_FANCY_NA;
170 status.engine = ENGINE_OFFLINE;
172 config.engine = (DEFAULT_ENGINE >= MAX_ENGINES) ? GNUCHESS : DEFAULT_ENGINE;
173 config.engine_cmd = enginecmd[config.engine];
174 config.jumpcount = 5;
175 config.clevel = 6;
176 config.book_method = (config.engine == GNUCHESS) ? BOOK_RANDOM : BOOK_OFF;
177 config.engine_depth = 0;
178 config.historyagony = 0;
179 config.agony = 1;
180 config.linegraphics = 0;
181 config.saveprompt = 1;
182 config.deleteprompt = 1;
183 config.validmoves = 1;
184 strncpy(config.ics_server, DEFAULT_ICS_SERVER, sizeof(config.ics_server));
185 config.ics_port = DEFAULT_ICS_PORT;
186 config.ics_user = DEFAULT_ICS_USER;
188 set_default_colors();
190 if (stat(config.nagfile, &st) == -1) {
191 if (errno == ENOENT)
192 copydatafile(config.nagfile, "nag.data");
193 else
194 warn("%s", config.nagfile);
197 if (stat(config.agonyfile, &st) == -1) {
198 if (errno == ENOENT)
199 copydatafile(config.agonyfile, "agony.data");
200 else
201 warn("%s", config.agonyfile);
204 if (stat(config.ccfile, &st) == -1) {
205 if (errno == ENOENT)
206 copydatafile(config.nagfile, "cc.data");
207 else
208 warn("%s", config.ccfile);
211 return;
214 void parse_rcfile(const char *filename)
216 FILE *fp;
217 char *line, buf[LINE_MAX];
218 int lines = 0;
219 char *altengine = NULL;
221 if ((fp = fopen(filename, "r")) == NULL)
222 err(EXIT_FAILURE, "%s", filename);
224 while ((line = fgets(buf, sizeof(buf), fp)) != NULL) {
225 int n;
226 char var[30], val[50];
227 char token[MAX_PGN_LINE_LEN + 1], value[MAX_PGN_LINE_LEN + 1];
229 lines++;
230 line = trim(line);
232 if (!line[0] || line[0] == '#')
233 continue;
235 if ((n = sscanf(line, "%s %[^\n]", var, val)) != 2)
236 errx(EXIT_FAILURE, "%s(%i): parse error %i", filename, lines,n);
238 strncpy(val, trim(val), sizeof(val));
239 strncpy(var, trim(var), sizeof(var));
241 if (strcmp(var, "book") == 0) {
242 if (strcmp(val, "prefer") == 0)
243 config.book_method = BOOK_PREFER;
244 else if (strcmp(val, "random") == 0)
245 config.book_method = BOOK_RANDOM;
246 else if (strcmp(val, "worst") == 0)
247 config.book_method = BOOK_WORST;
248 else if (strcmp(val, "best") == 0)
249 config.book_method = BOOK_BEST;
250 else if (strcmp(val, "off") == 0)
251 config.book_method = BOOK_OFF;
252 else
253 errx(EXIT_FAILURE, "%s(%i): invalid book method \"%s\"",
254 filename, lines, val);
256 else if (strcmp(var, "jumpcount") == 0) {
257 if (!isinteger(val))
258 errx(EXIT_FAILURE, "%s(%i): value is not an integer", filename,
259 lines);
261 config.jumpcount = atoi(val);
263 else if (strcmp(var, "depth") == 0) {
264 if (!isinteger(val))
265 errx(EXIT_FAILURE, "%s(%i): value is not an integer", filename,
266 lines);
268 config.engine_depth = atoi(val);
270 else if (strcmp(var, "historyagony") == 0)
271 config.historyagony = on_or_off(filename, lines, val);
272 else if (strcmp(var, "agony") == 0)
273 config.agony = on_or_off(filename, lines, val);
274 else if (strcmp(var, "pgntag") == 0) {
275 if ((n = sscanf(val, "%s %s ", token, value)) < 1 ||
276 n > 2)
277 errx(EXIT_FAILURE, "%s(%i): invalid value \"%s\"", filename,
278 lines, val);
280 if (n == 1)
281 value[0] = 0;
283 for (n = 0; n < strlen(token); n++) {
284 if (!isalnum(token[n]) && token[n] != '_')
285 errx(EXIT_FAILURE,
286 "%s(%i): token names must match 0-9A-Za-z_.",
287 filename, lines);
290 token[0] = toupper(token[0]);
291 add_tag(&config.tag, &config.tindex, token, value);
293 else if (strcmp(var, "board_window") == 0)
294 parse_color(filename, lines, val, &config.color[CONF_BDWINDOW]);
295 else if (strcmp(var, "board_selected") == 0)
296 parse_color(filename, lines, val, &config.color[CONF_BSELECTED]);
297 else if (strcmp(var, "board_white_moves") == 0)
298 parse_color(filename, lines, val, &config.color[CONF_BMOVESW]);
299 else if (strcmp(var, "board_black_moves") == 0)
300 parse_color(filename, lines, val, &config.color[CONF_BMOVESB]);
301 else if (strcmp(var, "board_count") == 0)
302 parse_color(filename, lines, val, &config.color[CONF_BCOUNT]);
303 else if (strcmp(var, "board_cursor") == 0)
304 parse_color(filename, lines, val, &config.color[CONF_BCURSOR]);
305 else if (strcmp(var, "board_black") == 0)
306 parse_color(filename, lines, val, &config.color[CONF_BBLACK]);
307 else if (strcmp(var, "board_white") == 0)
308 parse_color(filename, lines, val, &config.color[CONF_BWHITE]);
309 else if (strcmp(var, "board_graphics") == 0)
310 parse_color(filename, lines, val, &config.color[CONF_BGRAPHICS]);
311 else if (strcmp(var, "board_coords") == 0)
312 parse_color(filename, lines, val, &config.color[CONF_BCOORDS]);
313 else if (strcmp(var, "status_window") == 0)
314 parse_color(filename, lines, val, &config.color[CONF_SWINDOW]);
315 else if (strcmp(var, "status_title") == 0)
316 parse_color(filename, lines, val, &config.color[CONF_STITLE]);
317 else if (strcmp(var, "status_border") == 0)
318 parse_color(filename, lines, val, &config.color[CONF_SBORDER]);
319 else if (strcmp(var, "status_notify") == 0)
320 parse_color(filename, lines, val, &config.color[CONF_SNOTIFY]);
321 else if (strcmp(var, "status_engine") == 0)
322 parse_color(filename, lines, val, &config.color[CONF_SENGINE]);
323 else if (strcmp(var, "tag_window") == 0)
324 parse_color(filename, lines, val, &config.color[CONF_TWINDOW]);
325 else if (strcmp(var, "tag_title") == 0)
326 parse_color(filename, lines, val, &config.color[CONF_TTITLE]);
327 else if (strcmp(var, "tag_border") == 0)
328 parse_color(filename, lines, val, &config.color[CONF_TBORDER]);
329 else if (strcmp(var, "history_window") == 0)
330 parse_color(filename, lines, val, &config.color[CONF_HWINDOW]);
331 else if (strcmp(var, "history_title") == 0)
332 parse_color(filename, lines, val, &config.color[CONF_HTITLE]);
333 else if (strcmp(var, "history_border") == 0)
334 parse_color(filename, lines, val, &config.color[CONF_HBORDER]);
335 else if (strcmp(var, "message_window") == 0)
336 parse_color(filename, lines, val, &config.color[CONF_MWINDOW]);
337 else if (strcmp(var, "message_title") == 0)
338 parse_color(filename, lines, val, &config.color[CONF_MTITLE]);
339 else if (strcmp(var, "message_border") == 0)
340 parse_color(filename, lines, val, &config.color[CONF_MBORDER]);
341 else if (strcmp(var, "message_prompt") == 0)
342 parse_color(filename, lines, val, &config.color[CONF_MPROMPT]);
343 else if (strcmp(var, "input_window") == 0)
344 parse_color(filename, lines, val, &config.color[CONF_IWINDOW]);
345 else if (strcmp(var, "input_title") == 0)
346 parse_color(filename, lines, val, &config.color[CONF_ITITLE]);
347 else if (strcmp(var, "input_border") == 0)
348 parse_color(filename, lines, val, &config.color[CONF_IBORDER]);
349 else if (strcmp(var, "input_prompt") == 0)
350 parse_color(filename, lines, val, &config.color[CONF_IPROMPT]);
351 else if (strcmp(var, "save_directory") == 0)
352 config.savedirectory = strdup(tilde_expand(val));
353 else if (strcmp(var, "line_graphics") == 0)
354 config.linegraphics = on_or_off(filename, lines, val);
355 else if (strcmp(var, "save_prompt") == 0)
356 config.saveprompt = on_or_off(filename, lines, val);
357 else if (strcmp(var, "delete_prompt") == 0)
358 config.deleteprompt = on_or_off(filename, lines, val);
359 else if (strcmp(var, "valid_moves") == 0)
360 config.validmoves = on_or_off(filename, lines, val);
361 else if (strcmp(var, "clevel") == 0) {
362 if (!isinteger(val))
363 errx(EXIT_FAILURE, "%s(%i): value is not an integer", filename,
364 lines);
366 if ((config.clevel = atoi(val)) > 9 || config.clevel < 1)
367 errx(EXIT_FAILURE, "%s(%i): value must be between 1 and 9",
368 filename, lines);
370 else if (strcmp(var, "ics_server") == 0)
371 strncpy(config.ics_server, val, sizeof(config.ics_server));
372 else if (strcmp(var, "ics_port") == 0) {
373 if (!isinteger(val))
374 errx(EXIT_FAILURE, "%s(%i): value is not an integer", filename,
375 lines);
377 config.ics_port = atoi(val);
379 else if (strcmp(var, "ics_user") == 0)
380 config.ics_user = strdup(val);
381 else if (strcmp(var, "ics_passwd") == 0)
382 config.ics_passwd = strdup(val);
383 else if (strcmp(var, "engine_cmd") == 0)
384 altengine = strdup(val);
385 else if (strcmp(var, "engine") == 0) {
386 switch (atoi(val)) {
387 case 0:
388 config.engine_cmd = enginecmd[GNUCHESS];
389 config.engine = GNUCHESS;
390 break;
391 case 1:
392 config.engine_cmd = enginecmd[CRAFTY];
393 config.engine = CRAFTY;
394 break;
395 default:
396 errx(EXIT_FAILURE,
397 "%s(%i): engine must be 0 through %i", filename,
398 lines, MAX_ENGINES - 1);
401 else
402 errx(EXIT_FAILURE, "%s(%i): invalid parameter \"%s\"", filename,
403 lines, var);
406 fclose(fp);
408 if (altengine)
409 config.engine_cmd = altengine;
411 return;