ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/prefs.cpp
Revision: 1.13
Committed: 2002-01-15T14:58:32Z (22 years, 4 months ago) by cebix
Branch: MAIN
CVS Tags: nigel-build-12, nigel-build-13, snapshot-15012002
Changes since 1.12: +1 -1 lines
Log Message:
- documentation updates
- 2001 -> 2002
- version 0.9 -> 1.0

File Contents

# Content
1 /*
2 * prefs.cpp - Preferences handling
3 *
4 * Basilisk II (C) 1997-2002 Christian Bauer
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 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <ctype.h>
25
26 #include "sysdeps.h"
27 #include "sys.h"
28 #include "prefs.h"
29
30
31 // Prefs items are stored in a linked list of these nodes
32 struct prefs_node {
33 prefs_node *next;
34 const char *name;
35 prefs_type type;
36 void *data;
37 };
38
39 // List of prefs nodes
40 static prefs_node *the_prefs = NULL;
41
42 // Prototypes
43 static const prefs_desc *find_prefs_desc(const char *name);
44
45
46 /*
47 * Initialize preferences
48 */
49
50 void PrefsInit(int &argc, char **&argv)
51 {
52 // Set defaults
53 AddPrefsDefaults();
54 AddPlatformPrefsDefaults();
55
56 // Load preferences from settings file
57 LoadPrefs();
58
59 // Override prefs with command line options
60 for (int i=1; i<argc; i++) {
61
62 // Options are of the form '--keyword'
63 const char *option = argv[i];
64 if (strlen(option) < 3 || option[0] != '-' || option[1] != '-')
65 continue;
66 const char *keyword = option + 2;
67
68 // Find descriptor for keyword
69 const prefs_desc *d = find_prefs_desc(keyword);
70 if (d == NULL)
71 continue;
72 argv[i] = NULL;
73
74 // Get value
75 i++;
76 if (i >= argc) {
77 fprintf(stderr, "Option '%s' must be followed by a value\n", option);
78 continue;
79 }
80 const char *value = argv[i];
81 argv[i] = NULL;
82
83 // Add/replace prefs item
84 switch (d->type) {
85 case TYPE_STRING:
86 if (d->multiple)
87 PrefsAddString(keyword, value);
88 else
89 PrefsReplaceString(keyword, value);
90 break;
91
92 case TYPE_BOOLEAN: {
93 if (!strcmp(value, "true") || !strcmp(value, "on") || !strcmp(value, "yes"))
94 PrefsReplaceBool(keyword, true);
95 else if (!strcmp(value, "false") || !strcmp(value, "off") || !strcmp(value, "no"))
96 PrefsReplaceBool(keyword, false);
97 else
98 fprintf(stderr, "Value for option '%s' must be 'true' or 'false'\n", option);
99 break;
100 }
101
102 case TYPE_INT32:
103 PrefsReplaceInt32(keyword, atoi(value));
104 break;
105
106 default:
107 break;
108 }
109 }
110
111 // Remove processed arguments
112 for (int i=1; i<argc; i++) {
113 int k;
114 for (k=i; k<argc; k++)
115 if (argv[k] != NULL)
116 break;
117 if (k > i) {
118 k -= i;
119 for (int j=i+k; j<argc; j++)
120 argv[j-k] = argv[j];
121 argc -= k;
122 }
123 }
124 }
125
126
127 /*
128 * Deinitialize preferences
129 */
130
131 void PrefsExit(void)
132 {
133 // Free prefs list
134 prefs_node *p = the_prefs, *next;
135 while (p) {
136 next = p->next;
137 free((void *)p->name);
138 free(p->data);
139 delete p;
140 p = next;
141 }
142 the_prefs = NULL;
143 }
144
145
146 /*
147 * Print preferences options help
148 */
149
150 static void print_options(const prefs_desc *list)
151 {
152 while (list->type != TYPE_END) {
153 if (list->help) {
154 const char *typestr, *defstr;
155 char numstr[32];
156 switch (list->type) {
157 case TYPE_STRING:
158 typestr = "STRING";
159 defstr = PrefsFindString(list->name);
160 if (defstr == NULL)
161 defstr = "none";
162 break;
163 case TYPE_BOOLEAN:
164 typestr = "BOOL";
165 if (PrefsFindBool(list->name))
166 defstr = "true";
167 else
168 defstr = "false";
169 break;
170 case TYPE_INT32:
171 typestr = "NUMBER";
172 sprintf(numstr, "%d", PrefsFindInt32(list->name));
173 defstr = numstr;
174 break;
175 default:
176 typestr = "<unknown>";
177 defstr = "none";
178 break;
179 }
180 printf(" --%s %s\n %s [default=%s]\n", list->name, typestr, list->help, defstr);
181 }
182 list++;
183 }
184 }
185
186 void PrefsPrintUsage(void)
187 {
188 printf("\nGeneral options:\n");
189 print_options(common_prefs_items);
190 printf("\nPlatform-specific options:\n");
191 print_options(platform_prefs_items);
192 printf("\nBoolean options are specified as '--OPTION true|on|yes' or\n'--OPTION false|off|no'.\n");
193 }
194
195
196 /*
197 * Find preferences descriptor by keyword
198 */
199
200 static const prefs_desc *find_prefs_desc(const char *name, const prefs_desc *list)
201 {
202 while (list->type != TYPE_ANY) {
203 if (strcmp(list->name, name) == 0)
204 return list;
205 list++;
206 }
207 return NULL;
208 }
209
210 static const prefs_desc *find_prefs_desc(const char *name)
211 {
212 const prefs_desc *d = find_prefs_desc(name, common_prefs_items);
213 if (d == NULL)
214 d = find_prefs_desc(name, platform_prefs_items);
215 return d;
216 }
217
218
219 /*
220 * Set prefs items
221 */
222
223 static void add_data(const char *name, prefs_type type, void *data, int size)
224 {
225 void *d = malloc(size);
226 if (d == NULL)
227 return;
228 memcpy(d, data, size);
229 prefs_node *p = new prefs_node;
230 p->next = 0;
231 p->name = strdup(name);
232 p->type = type;
233 p->data = d;
234 if (the_prefs) {
235 prefs_node *prev = the_prefs;
236 while (prev->next)
237 prev = prev->next;
238 prev->next = p;
239 } else
240 the_prefs = p;
241 }
242
243 void PrefsAddString(const char *name, const char *s)
244 {
245 add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1);
246 }
247
248 void PrefsAddBool(const char *name, bool b)
249 {
250 add_data(name, TYPE_BOOLEAN, &b, sizeof(bool));
251 }
252
253 void PrefsAddInt32(const char *name, int32 val)
254 {
255 add_data(name, TYPE_INT32, &val, sizeof(int32));
256 }
257
258
259 /*
260 * Replace prefs items
261 */
262
263 static prefs_node *find_node(const char *name, prefs_type type, int index = 0)
264 {
265 prefs_node *p = the_prefs;
266 int i = 0;
267 while (p) {
268 if ((type == TYPE_ANY || p->type == type) && !strcmp(p->name, name)) {
269 if (i == index)
270 return p;
271 else
272 i++;
273 }
274 p = p->next;
275 }
276 return NULL;
277 }
278
279 void PrefsReplaceString(const char *name, const char *s, int index)
280 {
281 prefs_node *p = find_node(name, TYPE_STRING, index);
282 if (p) {
283 free(p->data);
284 p->data = strdup(s);
285 } else
286 add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1);
287 }
288
289 void PrefsReplaceBool(const char *name, bool b)
290 {
291 prefs_node *p = find_node(name, TYPE_BOOLEAN);
292 if (p)
293 *(bool *)(p->data) = b;
294 else
295 add_data(name, TYPE_BOOLEAN, &b, sizeof(bool));
296 }
297
298 void PrefsReplaceInt32(const char *name, int32 val)
299 {
300 prefs_node *p = find_node(name, TYPE_INT32);
301 if (p)
302 *(int32 *)(p->data) = val;
303 else
304 add_data(name, TYPE_INT32, &val, sizeof(int32));
305 }
306
307
308 /*
309 * Get prefs items
310 */
311
312 const char *PrefsFindString(const char *name, int index)
313 {
314 prefs_node *p = find_node(name, TYPE_STRING, index);
315 if (p)
316 return (char *)(p->data);
317 else
318 return NULL;
319 }
320
321 bool PrefsFindBool(const char *name)
322 {
323 prefs_node *p = find_node(name, TYPE_BOOLEAN, 0);
324 if (p)
325 return *(bool *)(p->data);
326 else
327 return false;
328 }
329
330 int32 PrefsFindInt32(const char *name)
331 {
332 prefs_node *p = find_node(name, TYPE_INT32, 0);
333 if (p)
334 return *(int32 *)(p->data);
335 else
336 return 0;
337 }
338
339
340 /*
341 * Remove prefs items
342 */
343
344 void PrefsRemoveItem(const char *name, int index)
345 {
346 prefs_node *p = find_node(name, TYPE_ANY, index);
347 if (p) {
348 free((void *)p->name);
349 free(p->data);
350 prefs_node *q = the_prefs;
351 if (q == p) {
352 the_prefs = NULL;
353 delete p;
354 return;
355 }
356 while (q) {
357 if (q->next == p) {
358 q->next = p->next;
359 delete p;
360 return;
361 }
362 q = q->next;
363 }
364 }
365 }
366
367
368 /*
369 * Load prefs from stream (utility function for LoadPrefs() implementation)
370 */
371
372 void LoadPrefsFromStream(FILE *f)
373 {
374 char line[256];
375 while(fgets(line, 255, f)) {
376 // Read line
377 int len = strlen(line);
378 if (len == 0)
379 continue;
380 line[len-1] = 0;
381
382 // Comments begin with "#" or ";"
383 if (line[0] == '#' || line[0] == ';')
384 continue;
385
386 // Terminate string after keyword
387 char *p = line;
388 while (!isspace(*p)) p++;
389 *p++ = 0;
390
391 // Skip whitespace until value
392 while (isspace(*p)) p++;
393 char *keyword = line;
394 char *value = p;
395 int32 i = atol(value);
396
397 // Look for keyword first in prefs item list
398 const prefs_desc *desc = find_prefs_desc(keyword);
399 if (desc == NULL) {
400 printf("WARNING: Unknown preferences keyword '%s'\n", keyword);
401 continue;
402 }
403
404 // Add item to prefs
405 switch (desc->type) {
406 case TYPE_STRING:
407 if (desc->multiple)
408 PrefsAddString(keyword, value);
409 else
410 PrefsReplaceString(keyword, value);
411 break;
412 case TYPE_BOOLEAN:
413 PrefsReplaceBool(keyword, !strcmp(value, "true"));
414 break;
415 case TYPE_INT32:
416 PrefsReplaceInt32(keyword, i);
417 break;
418 default:
419 break;
420 }
421 }
422 }
423
424
425 /*
426 * Save settings to stream (utility function for SavePrefs() implementation)
427 */
428
429 static void write_prefs(FILE *f, const prefs_desc *list)
430 {
431 while (list->type != TYPE_ANY) {
432 switch (list->type) {
433 case TYPE_STRING: {
434 int index = 0;
435 const char *str;
436 while ((str = PrefsFindString(list->name, index++)) != NULL)
437 fprintf(f, "%s %s\n", list->name, str);
438 break;
439 }
440 case TYPE_BOOLEAN:
441 fprintf(f, "%s %s\n", list->name, PrefsFindBool(list->name) ? "true" : "false");
442 break;
443 case TYPE_INT32:
444 fprintf(f, "%s %d\n", list->name, PrefsFindInt32(list->name));
445 break;
446 default:
447 break;
448 }
449 list++;
450 }
451 }
452
453 void SavePrefsToStream(FILE *f)
454 {
455 write_prefs(f, common_prefs_items);
456 write_prefs(f, platform_prefs_items);
457 }