2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
23 #define _WIN32_IE 0x501
25 #define _WIN32_IE 0x400
42 typedef struct ConfigEntry
{
47 typedef struct ConfigBlock
{
49 unsigned int entryCount
;
52 static ConfigBlock cfgBlock
;
54 static char buffer
[1024];
56 static char *lstrip(char *line
)
58 while(isspace(line
[0]))
63 static char *rstrip(char *line
)
65 size_t len
= strlen(line
);
66 while(len
> 0 && isspace(line
[len
-1]))
72 static void LoadConfigFromFile(FILE *f
)
74 char curSection
[128] = "";
77 while(fgets(buffer
, sizeof(buffer
), f
))
83 comment
= strchr(buffer
, '#');
87 comment
= rstrip(lstrip(comment
));
90 line
= rstrip(lstrip(buffer
));
96 char *section
= line
+1;
99 endsection
= strchr(section
, ']');
100 if(!endsection
|| section
== endsection
|| endsection
[1] != 0)
102 ERR("config parse error: bad line \"%s\"\n", line
);
107 if(strcasecmp(section
, "general") == 0)
111 strncpy(curSection
, section
, sizeof(curSection
)-1);
112 curSection
[sizeof(curSection
)-1] = 0;
118 if(sscanf(line
, "%255[^=] = \"%255[^\"]\"", key
, value
) == 2 ||
119 sscanf(line
, "%255[^=] = '%255[^\']'", key
, value
) == 2 ||
120 sscanf(line
, "%255[^=] = %255[^\n]", key
, value
) == 2)
122 /* sscanf doesn't handle '' or "" as empty values, so clip it
124 if(strcmp(value
, "\"\"") == 0 || strcmp(value
, "''") == 0)
127 else if(sscanf(line
, "%255[^=] %255[=]", key
, value
) == 2)
129 /* Special case for 'key =' */
134 ERR("config parse error: malformed option line: \"%s\"\n\n", line
);
139 if(curSection
[0] != 0)
141 size_t len
= strlen(curSection
);
142 memmove(&key
[len
+1], key
, sizeof(key
)-1-len
);
144 memcpy(key
, curSection
, len
);
147 /* Check if we already have this option set */
148 ent
= cfgBlock
.entries
;
149 while((unsigned int)(ent
-cfgBlock
.entries
) < cfgBlock
.entryCount
)
151 if(strcasecmp(ent
->key
, key
) == 0)
156 if((unsigned int)(ent
-cfgBlock
.entries
) >= cfgBlock
.entryCount
)
158 /* Allocate a new option entry */
159 ent
= realloc(cfgBlock
.entries
, (cfgBlock
.entryCount
+1)*sizeof(ConfigEntry
));
162 ERR("config parse error: error reallocating config entries\n");
165 cfgBlock
.entries
= ent
;
166 ent
= cfgBlock
.entries
+ cfgBlock
.entryCount
;
167 cfgBlock
.entryCount
++;
169 ent
->key
= strdup(key
);
174 ent
->value
= strdup(value
);
176 TRACE("found '%s' = '%s'\n", ent
->key
, ent
->value
);
180 void ReadALConfig(void)
186 if(SHGetSpecialFolderPathA(NULL
, buffer
, CSIDL_APPDATA
, FALSE
) != FALSE
)
188 size_t p
= strlen(buffer
);
189 snprintf(buffer
+p
, sizeof(buffer
)-p
, "\\alsoft.ini");
191 TRACE("Loading config %s...\n", buffer
);
192 f
= fopen(buffer
, "rt");
195 LoadConfigFromFile(f
);
200 str
= "/etc/openal/alsoft.conf";
202 TRACE("Loading config %s...\n", str
);
206 LoadConfigFromFile(f
);
210 if(!(str
=getenv("XDG_CONFIG_DIRS")) || str
[0] == 0)
212 strncpy(buffer
, str
, sizeof(buffer
)-1);
213 buffer
[sizeof(buffer
)-1] = 0;
214 /* Go through the list in reverse, since "the order of base directories
215 * denotes their importance; the first directory listed is the most
216 * important". Ergo, we need to load the settings from the later dirs
217 * first so that the settings in the earlier dirs override them.
221 char *next
= strrchr(buffer
, ':');
222 if(next
) *(next
++) = 0;
226 WARN("Ignoring XDG config dir: %s\n", next
);
229 size_t len
= strlen(next
);
230 strncpy(next
+len
, "/alsoft.conf", buffer
+sizeof(buffer
)-next
-len
);
231 buffer
[sizeof(buffer
)-1] = 0;
233 TRACE("Loading config %s...\n", next
);
234 f
= fopen(next
, "r");
237 LoadConfigFromFile(f
);
245 if((str
=getenv("HOME")) != NULL
&& *str
)
247 snprintf(buffer
, sizeof(buffer
), "%s/.alsoftrc", str
);
249 TRACE("Loading config %s...\n", buffer
);
250 f
= fopen(buffer
, "r");
253 LoadConfigFromFile(f
);
258 if((str
=getenv("XDG_CONFIG_HOME")) != NULL
&& str
[0] != 0)
259 snprintf(buffer
, sizeof(buffer
), "%s/%s", str
, "alsoft.conf");
263 if((str
=getenv("HOME")) != NULL
&& str
[0] != 0)
264 snprintf(buffer
, sizeof(buffer
), "%s/.config/%s", str
, "alsoft.conf");
268 TRACE("Loading config %s...\n", buffer
);
269 f
= fopen(buffer
, "r");
272 LoadConfigFromFile(f
);
278 if((str
=getenv("ALSOFT_CONF")) != NULL
&& *str
)
280 TRACE("Loading config %s...\n", str
);
284 LoadConfigFromFile(f
);
290 void FreeALConfig(void)
294 for(i
= 0;i
< cfgBlock
.entryCount
;i
++)
296 free(cfgBlock
.entries
[i
].key
);
297 free(cfgBlock
.entries
[i
].value
);
299 free(cfgBlock
.entries
);
302 const char *GetConfigValue(const char *blockName
, const char *keyName
, const char *def
)
310 if(blockName
&& strcasecmp(blockName
, "general") != 0)
311 snprintf(key
, sizeof(key
), "%s/%s", blockName
, keyName
);
314 strncpy(key
, keyName
, sizeof(key
)-1);
315 key
[sizeof(key
)-1] = 0;
318 for(i
= 0;i
< cfgBlock
.entryCount
;i
++)
320 if(strcasecmp(cfgBlock
.entries
[i
].key
, key
) == 0)
322 TRACE("Found %s = \"%s\"\n", key
, cfgBlock
.entries
[i
].value
);
323 if(cfgBlock
.entries
[i
].value
[0])
324 return cfgBlock
.entries
[i
].value
;
329 TRACE("Key %s not found\n", key
);
333 int ConfigValueExists(const char *blockName
, const char *keyName
)
335 const char *val
= GetConfigValue(blockName
, keyName
, "");
339 int ConfigValueStr(const char *blockName
, const char *keyName
, const char **ret
)
341 const char *val
= GetConfigValue(blockName
, keyName
, "");
342 if(!val
[0]) return 0;
348 int ConfigValueInt(const char *blockName
, const char *keyName
, int *ret
)
350 const char *val
= GetConfigValue(blockName
, keyName
, "");
351 if(!val
[0]) return 0;
353 *ret
= strtol(val
, NULL
, 0);
357 int ConfigValueUInt(const char *blockName
, const char *keyName
, unsigned int *ret
)
359 const char *val
= GetConfigValue(blockName
, keyName
, "");
360 if(!val
[0]) return 0;
362 *ret
= strtoul(val
, NULL
, 0);
366 int ConfigValueFloat(const char *blockName
, const char *keyName
, float *ret
)
368 const char *val
= GetConfigValue(blockName
, keyName
, "");
369 if(!val
[0]) return 0;
372 *ret
= strtof(val
, NULL
);
374 *ret
= (float)strtod(val
, NULL
);
379 int GetConfigValueBool(const char *blockName
, const char *keyName
, int def
)
381 const char *val
= GetConfigValue(blockName
, keyName
, "");
383 if(!val
[0]) return !!def
;
384 return (strcasecmp(val
, "true") == 0 || strcasecmp(val
, "yes") == 0 ||
385 strcasecmp(val
, "on") == 0 || atoi(val
) != 0);