3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
10 * By Shawn Hargreaves,
16 * Configuration routines.
18 * See readme.txt for copyright information.
31 typedef struct CONFIG_ENTRY
33 char *name; /* variable name (NULL if comment) */
34 char *data; /* variable value */
35 struct CONFIG_ENTRY *next; /* linked list */
41 CONFIG_ENTRY *head; /* linked list of config entries */
42 char *filename; /* where were we loaded from? */
43 int dirty; /* has our data changed? */
49 static CONFIG *config[MAX_CONFIGS] = { NULL, NULL, NULL, NULL };
50 static CONFIG *config_override = NULL;
52 static int config_installed = FALSE;
57 * Destroys a config structure, writing it out to disk if the contents
60 static void destroy_config(CONFIG *cfg)
62 CONFIG_ENTRY *pos, *prev;
67 /* write changed data to disk */
68 PACKFILE *f = pack_fopen(cfg->filename, F_WRITE);
75 pack_fputs(pos->name, f);
76 if (pos->name[0] != '[')
80 pack_fputs(pos->data, f);
93 /* destroy the variable list */
116 * Called at shutdown time to free memory being used by the config routines,
117 * and write any changed data out to disk.
119 static void config_cleanup()
123 for (i=0; i<MAX_CONFIGS; i++) {
125 destroy_config(config[i]);
130 if (config_override) {
131 destroy_config(config_override);
132 config_override = NULL;
135 _remove_exit_func(config_cleanup);
136 config_installed = FALSE;
142 * Sets up the configuration routines ready for use, also loading the
143 * default config file if the loaddata flag is set and no other config
146 static void init_config(int loaddata)
152 if (!config_installed) {
153 _add_exit_func(config_cleanup);
154 config_installed = TRUE;
157 if ((loaddata) && (!config[0])) {
158 /* look for allegro.cfg in the same directory as the program */
159 strcpy(buf[0], __crt0_argv[0]);
161 *get_filename(buf[0]) = 0;
162 put_backslash(buf[0]);
163 strcat(buf[0], "allegro.cfg");
165 /* if that fails, try sound.cfg */
166 strcpy(buf[1], __crt0_argv[0]);
168 *get_filename(buf[1]) = 0;
169 put_backslash(buf[1]);
170 strcat(buf[1], "sound.cfg");
172 /* no luck? try the ALLEGRO enviroment variable... */
173 s = getenv("ALLEGRO");
177 put_backslash(buf[2]);
178 strcat(buf[2], "allegro.cfg");
182 put_backslash(buf[3]);
183 strcat(buf[3], "sound.cfg");
186 strcpy(buf[2], buf[0]);
187 strcpy(buf[3], buf[1]);
190 /* see which of these files actually exist */
191 for (i=0; i<4; i++) {
192 if (file_exists(buf[i], FA_RDONLY | FA_ARCH, NULL)) {
193 set_config_file(buf[i]);
199 set_config_file(buf[0]);
206 * Helper for splitting files up into individual lines.
208 static int get_line(char *data, int length, char *name, char *val)
210 char buf[256], buf2[256];
213 for (pos=0; (pos<length) && (pos<255); pos++) {
214 if ((data[pos] == '\r') || (data[pos] == '\n')) {
216 if ((pos < length-1) &&
217 (((data[pos] == '\r') && (data[pos+1] == '\n')) ||
218 ((data[pos] == '\n') && (data[pos+1] == '\r')))) {
225 buf[pos] = data[pos];
228 buf[MIN(pos,255)] = 0;
230 /* skip leading spaces */
232 while ((buf[i]) && (isspace(buf[i])))
235 /* read name string */
237 while ((buf[i]) && (!isspace(buf[i])) && (buf[i] != '=') && (buf[i] != '#'))
238 buf2[j++] = buf[i++];
245 while ((buf[i]) && ((isspace(buf[i])) || (buf[i] == '=')))
250 /* strip trailing spaces */
252 while ((i >= 0) && (isspace(val[i])))
256 /* blank line or comment */
267 * Does the work of setting up a config structure.
269 static void set_config(CONFIG **config, char *data, int length, char *filename)
273 CONFIG_ENTRY **prev, *p;
279 destroy_config(*config);
283 *config = malloc(sizeof(CONFIG));
284 (*config)->head = NULL;
285 (*config)->dirty = FALSE;
288 (*config)->filename = malloc(strlen(filename)+1);
289 strcpy((*config)->filename, filename);
292 (*config)->filename = NULL;
294 prev = &(*config)->head;
297 while (pos < length) {
298 pos += get_line(data+pos, length-pos, name, val);
300 p = malloc(sizeof(CONFIG_ENTRY));
303 p->name = malloc(strlen(name)+1);
304 strcpy(p->name, name);
309 p->data = malloc(strlen(val)+1);
310 strcpy(p->data, val);
321 * Does the work of loading a config file.
323 static void load_config_file(CONFIG **config, char *filename, char *savefile)
325 int length = file_size(filename);
328 PACKFILE *f = pack_fopen(filename, F_READ);
330 char *tmp = malloc(length);
331 pack_fread(tmp, length, f);
333 set_config(config, tmp, length, savefile);
337 set_config(config, NULL, 0, savefile);
340 set_config(config, NULL, 0, savefile);
346 * Sets the file to be used for all future configuration operations.
348 void set_config_file(char *filename)
350 load_config_file(&config[0], filename, filename);
356 * Sets the block of data to be used for all future configuration
359 void set_config_data(char *data, int length)
361 set_config(&config[0], data, length, NULL);
366 /* override_config_file:
367 * Sets the file that will override all future configuration operations.
369 void override_config_file(char *filename)
371 load_config_file(&config_override, filename, NULL);
376 /* override_config_data:
377 * Sets the block of data that will override all future configuration
380 void override_config_data(char *data, int length)
382 set_config(&config_override, data, length, NULL);
387 /* push_config_state:
388 * Pushes the current config state onto the stack.
390 void push_config_state()
394 if (config[MAX_CONFIGS-1])
395 destroy_config(config[MAX_CONFIGS-1]);
397 for (i=MAX_CONFIGS-1; i>0; i--)
398 config[i] = config[i-1];
406 * Pops the current config state off the stack.
408 void pop_config_state()
413 destroy_config(config[0]);
415 for (i=0; i<MAX_CONFIGS-1; i++)
416 config[i] = config[i+1];
418 config[MAX_CONFIGS-1] = NULL;
423 /* prettify_section_name:
424 * Helper for ensuring that a section name is enclosed by [ ] braces.
426 static void prettify_section_name(char *in, char *out)
436 if (out[strlen(out)-1] != ']')
445 /* find_config_string:
446 * Helper for finding an entry in the configuration file.
448 static CONFIG_ENTRY *find_config_string(CONFIG *config, char *section, char *name, CONFIG_ENTRY **prev)
451 int in_section = TRUE;
452 char section_name[256];
454 prettify_section_name(section, section_name);
464 if ((p->name[0] == '[') && (p->name[strlen(p->name)-1] == ']')) {
466 in_section = (stricmp(section_name, p->name) == 0);
468 if ((in_section) || (name[0] == '[')) {
469 /* is this the one? */
470 if (stricmp(p->name, name) == 0)
487 /* get_config_string:
488 * Reads a string from the configuration file.
490 char *get_config_string(char *section, char *name, char *def)
496 p = find_config_string(config_override, section, name, NULL);
499 p = find_config_string(config[0], section, name, NULL);
502 return (p->data ? p->data : "");
510 * Reads an integer from the configuration file.
512 int get_config_int(char *section, char *name, int def)
514 char *s = get_config_string(section, name, NULL);
517 return strtol(s, NULL, 0);
525 * Reads a hexadecimal integer from the configuration file.
527 int get_config_hex(char *section, char *name, int def)
529 char *s = get_config_string(section, name, NULL);
533 i = strtol(s, NULL, 16);
534 if ((i == 0x7FFFFFFF) && (stricmp(s, "7FFFFFFF") != 0))
545 * Reads a float from the configuration file.
547 float get_config_float(char *section, char *name, float def)
549 char *s = get_config_string(section, name, NULL);
560 * Reads an argc/argv style token list from the configuration file.
562 char **get_config_argv(char *section, char *name, int *argc)
566 static char buf[256];
567 static char *argv[MAX_ARGV];
570 char *s = get_config_string(section, name, NULL);
581 while ((ac<MAX_ARGV) && (buf[pos]) && (buf[pos] != '#')) {
582 while ((buf[pos]) && (isspace(buf[pos])))
585 if ((buf[pos]) && (buf[pos] != '#')) {
586 argv[ac++] = buf+pos;
588 while ((buf[pos]) && (!isspace(buf[pos])))
603 * Helper for inserting a new variable into a configuration file.
605 static CONFIG_ENTRY *insert_variable(CONFIG_ENTRY *p, char *name, char *data)
607 CONFIG_ENTRY *n = malloc(sizeof(CONFIG_ENTRY));
610 n->name = malloc(strlen(name)+1);
611 strcpy(n->name, name);
617 n->data = malloc(strlen(data)+1);
618 strcpy(n->data, data);
637 /* set_config_string:
638 * Writes a string to the configuration file.
640 void set_config_string(char *section, char *name, char *val)
642 CONFIG_ENTRY *p, *prev;
643 char section_name[256];
648 p = find_config_string(config[0], section, name, &prev);
651 if ((val) && (*val)) {
652 /* modify existing variable */
656 p->data = malloc(strlen(val)+1);
657 strcpy(p->data, val);
660 /* delete variable */
668 prev->next = p->next;
670 config[0]->head = p->next;
676 if ((val) && (*val)) {
677 /* add a new variable */
678 prettify_section_name(section, section_name);
680 if (section_name[0]) {
681 p = find_config_string(config[0], NULL, section_name, &prev);
684 /* create a new section */
686 while ((p) && (p->next))
689 if ((p) && (p->data) && (*p->data))
690 p = insert_variable(p, NULL, NULL);
692 p = insert_variable(p, section_name, NULL);
695 /* append to the end of the section */
696 while ((p) && (p->next) &&
697 (((p->next->name) && (*p->next->name)) ||
698 ((p->next->data) && (*p->next->data))))
701 p = insert_variable(p, name, val);
704 /* global variable */
706 insert_variable(NULL, name, val);
707 config[0]->head->next = p;
712 config[0]->dirty = TRUE;
719 * Writes an integer to the configuration file.
721 void set_config_int(char *section, char *name, int val)
724 sprintf(buf, "%d", val);
725 set_config_string(section, name, buf);
731 * Writes a hexadecimal integer to the configuration file.
733 void set_config_hex(char *section, char *name, int val)
737 sprintf(buf, "%X", val);
738 set_config_string(section, name, buf);
741 set_config_string(section, name, "-1");
747 * Writes a float to the configuration file.
749 void set_config_float(char *section, char *name, float val)
752 sprintf(buf, "%f", val);
753 set_config_string(section, name, buf);