ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/prefs.cpp
Revision: 1.11
Committed: 2001-04-01T12:11:42Z (23 years, 1 month ago) by cebix
Branch: MAIN
Changes since 1.10: +94 -30 lines
Log Message:
- added help for command line options
- PrefsInit() removes all processed options

File Contents

# Content
1 /*
2 * prefs.cpp - Preferences handling
3 *
4 * Basilisk II (C) 1997-2001 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 }
143
144
145 /*
146 * Print preferences options help
147 */
148
149 static void print_options(const prefs_desc *list)
150 {
151 while (list->type != TYPE_END) {
152 if (list->help) {
153 const char *typestr, *defstr;
154 char numstr[32];
155 switch (list->type) {
156 case TYPE_STRING:
157 typestr = "STRING";
158 defstr = PrefsFindString(list->name);
159 if (defstr == NULL)
160 defstr = "none";
161 break;
162 case TYPE_BOOLEAN:
163 typestr = "BOOL";
164 if (PrefsFindBool(list->name))
165 defstr = "true";
166 else
167 defstr = "false";
168 break;
169 case TYPE_INT32:
170 typestr = "NUMBER";
171 sprintf(numstr, "%d", PrefsFindInt32(list->name));
172 defstr = numstr;
173 break;
174 default:
175 typestr = "<unknown>";
176 defstr = "none";
177 break;
178 }
179 printf(" --%s %s\n %s [default=%s]\n", list->name, typestr, list->help, defstr);
180 }
181 list++;
182 }
183 }
184
185 void PrefsPrintUsage(void)
186 {
187 printf("\nGeneral options:\n");
188 print_options(common_prefs_items);
189 printf("\nPlatform-specific options:\n");
190 print_options(platform_prefs_items);
191 printf("\nBoolean options are specified as '--OPTION true|on|yes' or\n'--OPTION false|off|no'.\n");
192 }
193
194
195 /*
196 * Find preferences descriptor by keyword
197 */
198
199 static const prefs_desc *find_prefs_desc(const char *name, const prefs_desc *list)
200 {
201 while (list->type != TYPE_ANY) {
202 if (strcmp(list->name, name) == 0)
203 return list;
204 list++;
205 }
206 return NULL;
207 }
208
209 static const prefs_desc *find_prefs_desc(const char *name)
210 {
211 const prefs_desc *d = find_prefs_desc(name, common_prefs_items);
212 if (d == NULL)
213 d = find_prefs_desc(name, platform_prefs_items);
214 return d;
215 }
216
217
218 /*
219 * Set prefs items
220 */
221
222 static void add_data(const char *name, prefs_type type, void *data, int size)
223 {
224 void *d = malloc(size);
225 if (d == NULL)
226 return;
227 memcpy(d, data, size);
228 prefs_node *p = new prefs_node;
229 p->next = 0;
230 p->name = strdup(name);
231 p->type = type;
232 p->data = d;
233 if (the_prefs) {
234 prefs_node *prev = the_prefs;
235 while (prev->next)
236 prev = prev->next;
237 prev->next = p;
238 } else
239 the_prefs = p;
240 }
241
242 void PrefsAddString(const char *name, const char *s)
243 {
244 add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1);
245 }
246
247 void PrefsAddBool(const char *name, bool b)
248 {
249 add_data(name, TYPE_BOOLEAN, &b, sizeof(bool));
250 }
251
252 void PrefsAddInt32(const char *name, int32 val)
253 {
254 add_data(name, TYPE_INT32, &val, sizeof(int32));
255 }
256
257
258 /*
259 * Replace prefs items
260 */
261
262 static prefs_node *find_node(const char *name, prefs_type type, int index = 0)
263 {
264 prefs_node *p = the_prefs;
265 int i = 0;
266 while (p) {
267 if ((type == TYPE_ANY || p->type == type) && !strcmp(p->name, name)) {
268 if (i == index)
269 return p;
270 else
271 i++;
272 }
273 p = p->next;
274 }
275 return NULL;
276 }
277
278 void PrefsReplaceString(const char *name, const char *s, int index)
279 {
280 prefs_node *p = find_node(name, TYPE_STRING, index);
281 if (p) {
282 free(p->data);
283 p->data = strdup(s);
284 } else
285 add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1);
286 }
287
288 void PrefsReplaceBool(const char *name, bool b)
289 {
290 prefs_node *p = find_node(name, TYPE_BOOLEAN);
291 if (p)
292 *(bool *)(p->data) = b;
293 else
294 add_data(name, TYPE_BOOLEAN, &b, sizeof(bool));
295 }
296
297 void PrefsReplaceInt32(const char *name, int32 val)
298 {
299 prefs_node *p = find_node(name, TYPE_INT32);
300 if (p)
301 *(int32 *)(p->data) = val;
302 else
303 add_data(name, TYPE_INT32, &val, sizeof(int32));
304 }
305
306
307 /*
308 * Get prefs items
309 */
310
311 const char *PrefsFindString(const char *name, int index)
312 {
313 prefs_node *p = find_node(name, TYPE_STRING, index);
314 if (p)
315 return (char *)(p->data);
316 else
317 return NULL;
318 }
319
320 bool PrefsFindBool(const char *name)
321 {
322 prefs_node *p = find_node(name, TYPE_BOOLEAN, 0);
323 if (p)
324 return *(bool *)(p->data);
325 else
326 return false;
327 }
328
329 int32 PrefsFindInt32(const char *name)
330 {
331 prefs_node *p = find_node(name, TYPE_INT32, 0);
332 if (p)
333 return *(int32 *)(p->data);
334 else
335 return 0;
336 }
337
338
339 /*
340 * Remove prefs items
341 */
342
343 void PrefsRemoveItem(const char *name, int index)
344 {
345 prefs_node *p = find_node(name, TYPE_ANY, index);
346 if (p) {
347 free((void *)p->name);
348 free(p->data);
349 prefs_node *q = the_prefs;
350 if (q == p) {
351 the_prefs = NULL;
352 delete p;
353 return;
354 }
355 while (q) {
356 if (q->next == p) {
357 q->next = p->next;
358 delete p;
359 return;
360 }
361 q = q->next;
362 }
363 }
364 }
365
366
367 /*
368 * Load prefs from stream (utility function for LoadPrefs() implementation)
369 */
370
371 void LoadPrefsFromStream(FILE *f)
372 {
373 char line[256];
374 while(fgets(line, 255, f)) {
375 // Read line
376 int len = strlen(line);
377 if (len == 0)
378 continue;
379 line[len-1] = 0;
380
381 // Comments begin with "#" or ";"
382 if (line[0] == '#' || line[0] == ';')
383 continue;
384
385 // Terminate string after keyword
386 char *p = line;
387 while (!isspace(*p)) p++;
388 *p++ = 0;
389
390 // Skip whitespace until value
391 while (isspace(*p)) p++;
392 char *keyword = line;
393 char *value = p;
394 int32 i = atol(value);
395
396 // Look for keyword first in prefs item list
397 const prefs_desc *desc = find_prefs_desc(keyword);
398 if (desc == NULL) {
399 printf("WARNING: Unknown preferences keyword '%s'\n", keyword);
400 continue;
401 }
402
403 // Add item to prefs
404 switch (desc->type) {
405 case TYPE_STRING:
406 if (desc->multiple)
407 PrefsAddString(keyword, value);
408 else
409 PrefsReplaceString(keyword, value);
410 break;
411 case TYPE_BOOLEAN:
412 PrefsReplaceBool(keyword, !strcmp(value, "true"));
413 break;
414 case TYPE_INT32:
415 PrefsReplaceInt32(keyword, i);
416 break;
417 default:
418 break;
419 }
420 }
421 }
422
423
424 /*
425 * Save settings to stream (utility function for SavePrefs() implementation)
426 */
427
428 static void write_prefs(FILE *f, const prefs_desc *list)
429 {
430 while (list->type != TYPE_ANY) {
431 switch (list->type) {
432 case TYPE_STRING: {
433 int index = 0;
434 const char *str;
435 while ((str = PrefsFindString(list->name, index++)) != NULL)
436 fprintf(f, "%s %s\n", list->name, str);
437 break;
438 }
439 case TYPE_BOOLEAN:
440 fprintf(f, "%s %s\n", list->name, PrefsFindBool(list->name) ? "true" : "false");
441 break;
442 case TYPE_INT32:
443 fprintf(f, "%s %d\n", list->name, PrefsFindInt32(list->name));
444 break;
445 default:
446 break;
447 }
448 list++;
449 }
450 }
451
452 void SavePrefsToStream(FILE *f)
453 {
454 write_prefs(f, common_prefs_items);
455 write_prefs(f, platform_prefs_items);
456 }