]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/allg_snd/sound/config.c
Removed automake stuff from "inert" subdirs. And there was much rejoicing.
[btb/d2x.git] / arch / dos / allg_snd / sound / config.c
1 /*         ______   ___    ___ 
2  *        /\  _  \ /\_ \  /\_ \ 
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *      By Shawn Hargreaves,
11  *      1 Salisbury Road,
12  *      Market Drayton,
13  *      Shropshire,
14  *      England, TF9 1AJ.
15  *
16  *      Configuration routines.
17  *
18  *      See readme.txt for copyright information.
19  */
20
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <strings.h>
25 #include <ctype.h>
26 #include <dir.h>
27
28 #include "allegro.h"
29 #include "internal.h"
30
31 typedef struct CONFIG_ENTRY
32 {
33    char *name;                      /* variable name (NULL if comment) */
34    char *data;                      /* variable value */
35    struct CONFIG_ENTRY *next;       /* linked list */
36 } CONFIG_ENTRY;
37
38
39 typedef struct CONFIG
40 {
41    CONFIG_ENTRY *head;              /* linked list of config entries */
42    char *filename;                  /* where were we loaded from? */
43    int dirty;                       /* has our data changed? */
44 } CONFIG;
45
46
47 #define MAX_CONFIGS     4
48
49 static CONFIG *config[MAX_CONFIGS] = { NULL, NULL, NULL, NULL };
50 static CONFIG *config_override = NULL;
51
52 static int config_installed = FALSE;
53
54
55
56 /* destroy_config:
57  *  Destroys a config structure, writing it out to disk if the contents
58  *  have changed.
59  */
60 static void destroy_config(CONFIG *cfg)
61 {
62    CONFIG_ENTRY *pos, *prev;
63
64    if (cfg) {
65       if (cfg->filename) {
66          if (cfg->dirty) {
67             /* write changed data to disk */
68             PACKFILE *f = pack_fopen(cfg->filename, F_WRITE);
69
70             if (f) {
71                pos = cfg->head;
72
73                while (pos) {
74                   if (pos->name) {
75                      pack_fputs(pos->name, f);
76                      if (pos->name[0] != '[')
77                         pack_fputs(" = ", f);
78                   }
79                   if (pos->data)
80                      pack_fputs(pos->data, f);
81
82                   pack_fputs("\n", f);
83                   pos = pos->next;
84                }
85
86                pack_fclose(f);
87             }
88          }
89
90          free(cfg->filename);
91       }
92
93       /* destroy the variable list */
94       pos = cfg->head;
95
96       while (pos) {
97          prev = pos;
98          pos = pos->next;
99
100          if (prev->name)
101             free(prev->name);
102
103          if (prev->data)
104             free(prev->data);
105
106          free(prev);
107       }
108
109       free(cfg);
110    }
111 }
112
113
114
115 /* config_cleanup:
116  *  Called at shutdown time to free memory being used by the config routines,
117  *  and write any changed data out to disk.
118  */
119 static void config_cleanup()
120 {
121    int i;
122
123    for (i=0; i<MAX_CONFIGS; i++) {
124       if (config[i]) {
125          destroy_config(config[i]);
126          config[i] = NULL;
127       }
128    }
129
130    if (config_override) {
131       destroy_config(config_override);
132       config_override = NULL;
133    }
134
135    _remove_exit_func(config_cleanup);
136    config_installed = FALSE;
137 }
138
139
140
141 /* init_config:
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
144  *  file is in memory.
145  */
146 static void init_config(int loaddata)
147 {
148    char buf[4][256];
149    char *s;
150    int i;
151
152    if (!config_installed) {
153       _add_exit_func(config_cleanup);
154       config_installed = TRUE;
155    }
156
157    if ((loaddata) && (!config[0])) {
158       /* look for allegro.cfg in the same directory as the program */
159       strcpy(buf[0], __crt0_argv[0]);
160       strlwr(buf[0]);
161       *get_filename(buf[0]) = 0;
162       put_backslash(buf[0]);
163       strcat(buf[0], "allegro.cfg");
164
165       /* if that fails, try sound.cfg */
166       strcpy(buf[1], __crt0_argv[0]);
167       strlwr(buf[1]);
168       *get_filename(buf[1]) = 0;
169       put_backslash(buf[1]);
170       strcat(buf[1], "sound.cfg");
171
172       /* no luck? try the ALLEGRO enviroment variable... */
173       s = getenv("ALLEGRO");
174       if (s) {
175          strcpy(buf[2], s);
176          strlwr(buf[2]);
177          put_backslash(buf[2]);
178          strcat(buf[2], "allegro.cfg");
179
180          strcpy(buf[3], s);
181          strlwr(buf[3]);
182          put_backslash(buf[3]);
183          strcat(buf[3], "sound.cfg");
184       }
185       else {
186          strcpy(buf[2], buf[0]);
187          strcpy(buf[3], buf[1]);
188       }
189
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]);
194             break;
195          }
196       }
197
198       if (i >= 4)
199          set_config_file(buf[0]);
200    }
201 }
202
203
204
205 /* get_line: 
206  *  Helper for splitting files up into individual lines.
207  */
208 static int get_line(char *data, int length, char *name, char *val)
209 {
210    char buf[256], buf2[256];
211    int pos, i, j;
212
213    for (pos=0; (pos<length) && (pos<255); pos++) {
214       if ((data[pos] == '\r') || (data[pos] == '\n')) {
215          buf[pos] = 0;
216          if ((pos < length-1) && 
217              (((data[pos] == '\r') && (data[pos+1] == '\n')) ||
218               ((data[pos] == '\n') && (data[pos+1] == '\r')))) {
219             pos++;
220          }
221          pos++;
222          break;
223       }
224
225       buf[pos] = data[pos];
226    }
227
228    buf[MIN(pos,255)] = 0;
229
230    /* skip leading spaces */
231    i = 0;
232    while ((buf[i]) && (isspace(buf[i])))
233       i++;
234
235    /* read name string */
236    j = 0;
237    while ((buf[i]) && (!isspace(buf[i])) && (buf[i] != '=') && (buf[i] != '#'))
238       buf2[j++] = buf[i++];
239
240    if (j) {
241       /* got a variable */
242       buf2[j] = 0;
243       strcpy(name, buf2);
244
245       while ((buf[i]) && ((isspace(buf[i])) || (buf[i] == '=')))
246          i++;
247
248       strcpy(val, buf+i);
249
250       /* strip trailing spaces */
251       i = strlen(val) - 1;
252       while ((i >= 0) && (isspace(val[i])))
253          val[i--] = 0;
254    }
255    else {
256       /* blank line or comment */
257       name[0] = 0;
258       strcpy(val, buf);
259    }
260
261    return pos;
262 }
263
264
265
266 /* set_config:
267  *  Does the work of setting up a config structure.
268  */
269 static void set_config(CONFIG **config, char *data, int length, char *filename)
270 {
271    char name[256];
272    char val[256];
273    CONFIG_ENTRY **prev, *p;
274    int pos;
275
276    init_config(FALSE);
277
278    if (*config) {
279       destroy_config(*config);
280       *config = NULL;
281    }
282
283    *config = malloc(sizeof(CONFIG));
284    (*config)->head = NULL;
285    (*config)->dirty = FALSE;
286
287    if (filename) {
288       (*config)->filename = malloc(strlen(filename)+1);
289       strcpy((*config)->filename, filename); 
290    }
291    else
292       (*config)->filename = NULL;
293
294    prev = &(*config)->head;
295    pos = 0;
296
297    while (pos < length) {
298       pos += get_line(data+pos, length-pos, name, val);
299
300       p = malloc(sizeof(CONFIG_ENTRY));
301
302       if (name[0]) {
303          p->name = malloc(strlen(name)+1);
304          strcpy(p->name, name);
305       }
306       else
307          p->name = NULL;
308
309       p->data = malloc(strlen(val)+1);
310       strcpy(p->data, val);
311
312       p->next = NULL;
313       *prev = p;
314       prev = &p->next;
315    }
316 }
317
318
319
320 /* load_config_file:
321  *  Does the work of loading a config file.
322  */
323 static void load_config_file(CONFIG **config, char *filename, char *savefile)
324 {
325    int length = file_size(filename);
326
327    if (length > 0) {
328       PACKFILE *f = pack_fopen(filename, F_READ);
329       if (f) {
330          char *tmp = malloc(length);
331          pack_fread(tmp, length, f);
332          pack_fclose(f);
333          set_config(config, tmp, length, savefile);
334          free(tmp);
335       }
336       else
337          set_config(config, NULL, 0, savefile);
338    }
339    else
340       set_config(config, NULL, 0, savefile);
341 }
342
343
344
345 /* set_config_file:
346  *  Sets the file to be used for all future configuration operations.
347  */
348 void set_config_file(char *filename)
349 {
350    load_config_file(&config[0], filename, filename);
351 }
352
353
354
355 /* set_config_data:
356  *  Sets the block of data to be used for all future configuration 
357  *  operations.
358  */
359 void set_config_data(char *data, int length)
360 {
361    set_config(&config[0], data, length, NULL);
362 }
363
364
365
366 /* override_config_file:
367  *  Sets the file that will override all future configuration operations.
368  */
369 void override_config_file(char *filename)
370 {
371    load_config_file(&config_override, filename, NULL);
372 }
373
374
375
376 /* override_config_data:
377  *  Sets the block of data that will override all future configuration 
378  *  operations.
379  */
380 void override_config_data(char *data, int length)
381 {
382    set_config(&config_override, data, length, NULL);
383 }
384
385
386
387 /* push_config_state:
388  *  Pushes the current config state onto the stack.
389  */
390 void push_config_state()
391 {
392    int i;
393
394    if (config[MAX_CONFIGS-1])
395       destroy_config(config[MAX_CONFIGS-1]);
396
397    for (i=MAX_CONFIGS-1; i>0; i--)
398       config[i] = config[i-1];
399
400    config[0] = NULL;
401 }
402
403
404
405 /* pop_config_state:
406  *  Pops the current config state off the stack.
407  */
408 void pop_config_state()
409 {
410    int i;
411
412    if (config[0])
413       destroy_config(config[0]);
414
415    for (i=0; i<MAX_CONFIGS-1; i++)
416       config[i] = config[i+1];
417
418    config[MAX_CONFIGS-1] = NULL;
419 }
420
421
422
423 /* prettify_section_name:
424  *  Helper for ensuring that a section name is enclosed by [ ] braces.
425  */
426 static void prettify_section_name(char *in, char *out)
427 {
428    if (in) {
429       if (in[0] != '[')
430          strcpy(out, "[");
431       else
432          out[0] = 0;
433
434       strcat(out, in);
435
436       if (out[strlen(out)-1] != ']')
437          strcat(out, "]");
438    }
439    else
440       out[0] = 0;
441 }
442
443
444
445 /* find_config_string:
446  *  Helper for finding an entry in the configuration file.
447  */
448 static CONFIG_ENTRY *find_config_string(CONFIG *config, char *section, char *name, CONFIG_ENTRY **prev)
449 {
450    CONFIG_ENTRY *p;
451    int in_section = TRUE;
452    char section_name[256];
453
454    prettify_section_name(section, section_name);
455
456    if (config) {
457       p = config->head;
458
459       if (prev)
460          *prev = NULL;
461
462       while (p) {
463          if (p->name) {
464             if ((p->name[0] == '[') && (p->name[strlen(p->name)-1] == ']')) {
465                /* change section */
466                in_section = (stricmp(section_name, p->name) == 0);
467             }
468             if ((in_section) || (name[0] == '[')) {
469                /* is this the one? */
470                if (stricmp(p->name, name) == 0)
471                   return p;
472             }
473          }
474
475          if (prev)
476             *prev = p;
477
478          p = p->next;
479       }
480    }
481
482    return NULL;
483 }
484
485
486
487 /* get_config_string:
488  *  Reads a string from the configuration file.
489  */
490 char *get_config_string(char *section, char *name, char *def)
491 {
492    CONFIG_ENTRY *p;
493
494    init_config(TRUE);
495
496    p = find_config_string(config_override, section, name, NULL);
497
498    if (!p)
499       p = find_config_string(config[0], section, name, NULL);
500
501    if (p)
502       return (p->data ? p->data : "");
503    else
504       return def;
505 }
506
507
508
509 /* get_config_int:
510  *  Reads an integer from the configuration file.
511  */
512 int get_config_int(char *section, char *name, int def)
513 {
514    char *s = get_config_string(section, name, NULL);
515
516    if ((s) && (*s))
517       return strtol(s, NULL, 0);
518
519    return def;
520 }
521
522
523
524 /* get_config_hex:
525  *  Reads a hexadecimal integer from the configuration file.
526  */
527 int get_config_hex(char *section, char *name, int def)
528 {
529    char *s = get_config_string(section, name, NULL);
530    int i;
531
532    if ((s) && (*s)) {
533       i = strtol(s, NULL, 16);
534       if ((i == 0x7FFFFFFF) && (stricmp(s, "7FFFFFFF") != 0))
535          i = -1;
536       return i;
537    }
538
539    return def;
540 }
541
542
543
544 /* get_config_float:
545  *  Reads a float from the configuration file.
546  */
547 float get_config_float(char *section, char *name, float def)
548 {
549    char *s = get_config_string(section, name, NULL);
550
551    if ((s) && (*s))
552       return atof(s);
553
554    return def;
555 }
556
557
558
559 /* get_config_argv:
560  *  Reads an argc/argv style token list from the configuration file.
561  */
562 char **get_config_argv(char *section, char *name, int *argc)
563 {
564    #define MAX_ARGV  16
565
566    static char buf[256];
567    static char *argv[MAX_ARGV];
568    int pos, ac;
569
570    char *s = get_config_string(section, name, NULL);
571
572    if (!s) {
573       *argc = 0;
574       return NULL;
575    }
576
577    strcpy(buf, s);
578    pos = 0;
579    ac = 0;
580
581    while ((ac<MAX_ARGV) && (buf[pos]) && (buf[pos] != '#')) {
582       while ((buf[pos]) && (isspace(buf[pos])))
583          pos++;
584
585       if ((buf[pos]) && (buf[pos] != '#')) {
586          argv[ac++] = buf+pos;
587
588          while ((buf[pos]) && (!isspace(buf[pos])))
589             pos++;
590
591          if (buf[pos])
592             buf[pos++] = 0;
593       }
594    }
595
596    *argc = ac;
597    return argv;
598 }
599
600
601
602 /* insert_variable:
603  *  Helper for inserting a new variable into a configuration file.
604  */
605 static CONFIG_ENTRY *insert_variable(CONFIG_ENTRY *p, char *name, char *data)
606 {
607    CONFIG_ENTRY *n = malloc(sizeof(CONFIG_ENTRY));
608
609    if (name) {
610       n->name = malloc(strlen(name)+1);
611       strcpy(n->name, name);
612    }
613    else
614       n->name = NULL;
615
616    if (data) {
617       n->data = malloc(strlen(data)+1);
618       strcpy(n->data, data);
619    }
620    else
621       n->data = NULL;
622
623    if (p) {
624       n->next = p->next;
625       p->next = n; 
626    }
627    else {
628       n->next = NULL;
629       config[0]->head = n;
630    }
631
632    return n;
633 }
634
635
636
637 /* set_config_string:
638  *  Writes a string to the configuration file.
639  */
640 void set_config_string(char *section, char *name, char *val)
641 {
642    CONFIG_ENTRY *p, *prev;
643    char section_name[256];
644
645    init_config(TRUE);
646
647    if (config[0]) {
648       p = find_config_string(config[0], section, name, &prev);
649
650       if (p) {
651          if ((val) && (*val)) {
652             /* modify existing variable */
653             if (p->data)
654                free(p->data);
655
656             p->data = malloc(strlen(val)+1);
657             strcpy(p->data, val);
658          }
659          else {
660             /* delete variable */
661             if (p->name)
662                free(p->name);
663
664             if (p->data)
665                free(p->data);
666
667             if (prev)
668                prev->next = p->next;
669             else
670                config[0]->head = p->next;
671
672             free(p);
673          }
674       }
675       else {
676          if ((val) && (*val)) {
677             /* add a new variable */
678             prettify_section_name(section, section_name);
679
680             if (section_name[0]) {
681                p = find_config_string(config[0], NULL, section_name, &prev);
682
683                if (!p) {
684                   /* create a new section */
685                   p = config[0]->head;
686                   while ((p) && (p->next))
687                      p = p->next;
688
689                   if ((p) && (p->data) && (*p->data))
690                      p = insert_variable(p, NULL, NULL);
691
692                   p = insert_variable(p, section_name, NULL);
693                }
694
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))))
699                   p = p->next;
700
701                p = insert_variable(p, name, val);
702             }
703             else {
704                /* global variable */
705                p = config[0]->head;
706                insert_variable(NULL, name, val);
707                config[0]->head->next = p;
708             }
709          } 
710       }
711
712       config[0]->dirty = TRUE;
713    }
714 }
715
716
717
718 /* set_config_int:
719  *  Writes an integer to the configuration file.
720  */
721 void set_config_int(char *section, char *name, int val)
722 {
723    char buf[32];
724    sprintf(buf, "%d", val);
725    set_config_string(section, name, buf);
726 }
727
728
729
730 /* set_config_hex:
731  *  Writes a hexadecimal integer to the configuration file.
732  */
733 void set_config_hex(char *section, char *name, int val)
734 {
735    if (val >= 0) {
736       char buf[32];
737       sprintf(buf, "%X", val);
738       set_config_string(section, name, buf);
739    }
740    else
741       set_config_string(section, name, "-1");
742 }
743
744
745
746 /* set_config_float:
747  *  Writes a float to the configuration file.
748  */
749 void set_config_float(char *section, char *name, float val)
750 {
751    char buf[32];
752    sprintf(buf, "%f", val);
753    set_config_string(section, name, buf);
754 }
755