]> git.pond.sub.org Git - empserver/blob - src/lib/gen/emp_config.c
Update copyright notice.
[empserver] / src / lib / gen / emp_config.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  emp_config.c: Allows config file to control server config. from a file
29  * 
30  *  Known contributors to this file:
31  *     Julian Onions, 1995
32  *     Steve McClure, 1998-2000
33  */
34
35 /*
36  * STILL TO DO
37  *
38  * 1. Change other constants - such as Num Countries etc.
39  *    Just requires variables to be assigned, then dynamic allocation in
40  *    a few places. Some checks needed in the server to check the world
41  *    hasn't changed size etc.
42  * 2. Could look at loading in planes, units etc. Should be easy enough.
43  *
44  */
45
46 #include <assert.h>
47 #include <errno.h>
48 #include <stdio.h>
49 #include <stdlib.h>             /* atoi free atol */
50 #include <string.h>
51
52 #include "misc.h"
53 #include "com.h"
54 #include "match.h"
55 #include "file.h"
56 #include "optlist.h"
57 #include "tel.h"
58 #include "gen.h"                /* parse */
59
60 /* for systems without strdup  */
61 #ifdef NOSTRDUP
62 extern char *strdup();
63 #endif /* NOSTRDUP */
64
65 /* Dummy one */
66 static int emp_config_dummy;
67
68 /* things that can be changed */
69 struct keymatch configkeys[] = {
70 #define EMP_CONFIG_C_OUTPUT
71 #include "econfig-spec.h"
72 #undef  EMP_CONFIG_C_OUTPUT
73 };
74
75 static void fixup_files(void);
76 static struct keymatch *keylookup(s_char *key, struct keymatch tbl[]);
77 static int set_option(const char *, int);
78
79 /*
80  * read in empire configuration
81  */
82 int
83 emp_config(char *file)
84 {
85     FILE *fp;
86     char scanspace[1024];
87     char *av[65];
88     char buf[BUFSIZ];
89     struct keymatch *kp;
90     int lno = 0;
91     int errors = 0;
92     int i;
93
94     if (file == NULL) {
95         fixup_files();
96         return 0;
97     }
98     if ((fp = fopen(file, "r")) == NULL) {
99         fprintf(stderr, "Can't open %s for reading (%s)\n",
100                 file, strerror(errno));
101         return -1;
102     }
103
104     while (fgets(buf, sizeof buf, fp) != NULL) {
105         ++lno;
106         for (i = 0; buf[i] && isspace(buf[i]); ++i) ;
107         if (!buf[i] || buf[i] == '#')
108             continue;
109         if (parse(buf, av, 0, scanspace, 0) < 0) {
110             fprintf(stderr, "%s:%d: Can't parse line %s", file, lno, buf);
111             errors = 1;
112             continue;
113         }
114         if ((kp = keylookup(av[0], configkeys)) == NULL) {
115             fprintf(stderr, "%s:%d: Unknown config key %s\n",
116                     file, lno, av[0]);
117             errors = 1;
118             continue;
119         }
120         if (av[1] == NULL) {
121             fprintf(stderr, "%s:%d: Config key %s needs a value\n",
122                     file, lno, av[0]);
123             errors = 1;
124             continue;
125         }
126         i = 2;
127         switch (kp->km_type) {
128         case NSC_INT:
129             *(int *)kp->km_data = atoi(av[1]);
130             break;
131         case NSC_FLOAT:
132             *(float *)kp->km_data = atof(av[1]);
133             break;
134         case NSC_DOUBLE:
135             *(double *)kp->km_data = atof(av[1]);
136             break;
137         case NSC_LONG:
138             *(long *)kp->km_data = atol(av[1]);
139             break;
140         case NSC_STRING:
141             if (kp->km_flags & KM_ALLOC)
142                 free(*(char **)kp->km_data);
143             *(char **)kp->km_data = strdup(av[1]);
144             kp->km_flags |= KM_ALLOC;
145             break;
146         case NSC_NOTYPE:
147             for (i = 1; av[i]; ++i) {
148                 if (set_option(av[i], kp->km_key[0] != 'n') < 0) {
149                     fprintf(stderr, "%s:%d: Unknown option %s\n",
150                             file, lno, av[i]);
151                     errors = 1;
152                 }
153             }
154             break;
155         default:
156             assert(0);
157         }
158         if (av[i] != NULL) {
159             fprintf(stderr, "%s:%d: Junk after value of config key %s\n",
160                     file, lno, av[0]);
161             errors = 1;
162         }
163     }
164     fclose(fp);
165     fixup_files();
166     WORLD_X &= ~1;              /* make even */
167
168     return -errors;
169 }
170
171 struct otherfiles {
172     char **files;
173     char *name;
174 };
175
176 /* list of other well known files... -maybe tailor these oneday
177  * anyway - meantime they are all relative to datadir */
178 static struct otherfiles ofiles[] = {
179     {&upfil, "up"},
180     {&downfil, "down"},
181     {&disablefil, "disable"},
182     {&banfil, "ban"},
183     {&authfil, "auth"},
184     {&annfil, "ann"},
185     {&timestampfil, "timestamp"},
186     {&teldir, "tel"},
187 #if !defined(_WIN32)
188     {&telfil, "tel/tel"},
189 #else
190     {&telfil, "tel\\tel"},
191 #endif
192     {NULL, NULL}
193 };
194
195 /* fix up the empfile struct to reference full path names */
196 static void
197 fixup_files(void)
198 {
199     struct empfile *ep;
200     struct otherfiles *op;
201     s_char buf[1024];
202
203     for (ep = empfile; ep < &empfile[EF_MAX]; ep++) {
204 #if !defined(_WIN32)
205         sprintf(buf, "%s/%s", datadir, ep->name);
206 #else
207         sprintf(buf, "%s\\%s", datadir, ep->name);
208 #endif
209         ep->file = strdup(buf);
210     }
211
212     for (op = ofiles; op->files; op++) {
213 #if !defined(_WIN32)
214         sprintf(buf, "%s/%s", datadir, op->name);
215 #else
216         sprintf(buf, "%s\\%s", datadir, op->name);
217 #endif
218         *op->files = strdup(buf);
219     }
220 }
221
222 /* find the key in the table */
223 static struct keymatch *
224 keylookup(register s_char *command, struct keymatch *tbl)
225 {
226     register struct keymatch *kp;
227
228     if (command == 0 || *command == 0)
229         return 0;
230     for (kp = tbl; kp->km_key != 0; kp++) {
231         if (strcmp(kp->km_key, command) == 0)
232             return kp;
233     }
234     return NULL;
235 }
236
237 void
238 print_config(FILE *fp)
239 {
240     struct empfile *ep;
241     struct option_list *op;
242     struct otherfiles *ofp;
243     struct keymatch *kp;
244
245     fprintf(fp, "# Empire Configuration File:\n");
246     for (kp = configkeys; kp->km_key; kp++) {
247         if (kp->km_comment)
248             fprintf(fp, "\n# %s\n", kp->km_comment);
249         if (!kp->km_key[0])
250             continue;
251         switch (kp->km_type) {
252         case NSC_STRING:
253             fprintf(fp, "%s \"%s\"\n", kp->km_key, *(char **)kp->km_data);
254             break;
255         case NSC_INT:
256             fprintf(fp, "%s %d\n", kp->km_key, *(int *)kp->km_data);
257             break;
258         case NSC_FLOAT:
259             fprintf(fp, "%s %g\n", kp->km_key, *(float *)kp->km_data);
260             break;
261         case NSC_DOUBLE:
262             fprintf(fp, "%s %g\n", kp->km_key, *(double *)kp->km_data);
263             break;
264         case NSC_LONG:
265             fprintf(fp, "%s %ld\n", kp->km_key, *(long *)kp->km_data);
266             break;
267         case NSC_NOTYPE:
268             for (op = Options; op->opt_key; op++)
269                 if (*op->opt_valuep != (kp->km_key[0] == 'n'))
270                     fprintf(fp, "%s %s\n", kp->km_key, op->opt_key);
271             break;
272         default:
273             assert(0);
274         }
275     }
276
277     fprintf(fp, "\n");
278     for (ep = empfile; ep < &empfile[EF_MAX]; ep++)
279         fprintf(fp, "# File %s -> %s\n", ep->name, ep->file);
280     for (ofp = ofiles; ofp->files; ofp++)
281         fprintf(fp, "# File %s -> %s\n", ofp->name, *(ofp->files));
282
283 }
284
285
286 /* Set option S to value VAL; return 0 on success, -1 on failure.  */
287 static int
288 set_option(const char *s, int val)
289 {
290     struct option_list *op;
291
292     for (op = Options; op->opt_key; op++) {
293         if (strcmp(op->opt_key, s) == 0) {
294             *op->opt_valuep = val;
295             return 0;
296         }
297     }
298     return -1;
299 }