Clamp source position to the buffer size when it stops
[openal-soft.git] / Alc / alcConfig.c
blobd5f4fb5ec8e863b8b4d520410df5e40cde003e46
1 /**
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <string.h>
28 #include "alMain.h"
30 #ifdef _WIN32
31 #define _WIN32_IE 0x400
32 #include <shlobj.h>
33 #endif
35 typedef struct ConfigEntry {
36 char *key;
37 char *value;
38 } ConfigEntry;
40 typedef struct ConfigBlock {
41 char *name;
42 ConfigEntry *entries;
43 size_t entryCount;
44 } ConfigBlock;
46 static ConfigBlock *cfgBlocks;
47 static size_t cfgCount;
49 static char buffer[1024];
51 static void LoadConfigFromFile(FILE *f)
53 ConfigBlock *curBlock = cfgBlocks;
54 ConfigEntry *ent;
56 while(fgets(buffer, sizeof(buffer), f))
58 size_t i = 0;
60 while(isspace(buffer[i]))
61 i++;
62 if(!buffer[i] || buffer[i] == '#')
63 continue;
65 memmove(buffer, buffer+i, strlen(buffer+i)+1);
67 if(buffer[0] == '[')
69 ConfigBlock *nextBlock;
71 i = 1;
72 while(buffer[i] && buffer[i] != ']')
73 i++;
75 if(!buffer[i])
77 AL_PRINT("config parse error: bad line \"%s\"\n", buffer);
78 continue;
80 buffer[i] = 0;
82 do {
83 i++;
84 if(buffer[i] && !isspace(buffer[i]))
86 if(buffer[i] != '#')
87 AL_PRINT("config warning: extra data after block: \"%s\"\n", buffer+i);
88 break;
90 } while(buffer[i]);
92 nextBlock = NULL;
93 for(i = 0;i < cfgCount;i++)
95 if(strcasecmp(cfgBlocks[i].name, buffer+1) == 0)
97 nextBlock = cfgBlocks+i;
98 // AL_PRINT("found block '%s'\n", nextBlock->name);
99 break;
103 if(!nextBlock)
105 nextBlock = realloc(cfgBlocks, (cfgCount+1)*sizeof(ConfigBlock));
106 if(!nextBlock)
108 AL_PRINT("config parse error: error reallocating config blocks\n");
109 continue;
111 cfgBlocks = nextBlock;
112 nextBlock = cfgBlocks+cfgCount;
113 cfgCount++;
115 nextBlock->name = strdup(buffer+1);
116 nextBlock->entries = NULL;
117 nextBlock->entryCount = 0;
119 // AL_PRINT("found new block '%s'\n", nextBlock->name);
121 curBlock = nextBlock;
122 continue;
125 /* Look for the option name */
126 i = 0;
127 while(buffer[i] && buffer[i] != '#' && buffer[i] != '=' &&
128 !isspace(buffer[i]))
129 i++;
131 if(!buffer[i] || buffer[i] == '#' || i == 0)
133 AL_PRINT("config parse error: malformed option line: \"%s\"\n", buffer);
134 continue;
137 /* Seperate the option */
138 if(buffer[i] != '=')
140 buffer[i++] = 0;
142 while(isspace(buffer[i]))
143 i++;
144 if(buffer[i] != '=')
146 AL_PRINT("config parse error: option without a value: \"%s\"\n", buffer);
147 continue;
150 /* Find the start of the value */
151 buffer[i++] = 0;
152 while(isspace(buffer[i]))
153 i++;
155 /* Check if we already have this option set */
156 ent = curBlock->entries;
157 while((size_t)(ent-curBlock->entries) < curBlock->entryCount)
159 if(strcasecmp(ent->key, buffer) == 0)
160 break;
161 ent++;
164 if((size_t)(ent-curBlock->entries) >= curBlock->entryCount)
166 /* Allocate a new option entry */
167 ent = realloc(curBlock->entries, (curBlock->entryCount+1)*sizeof(ConfigEntry));
168 if(!ent)
170 AL_PRINT("config parse error: error reallocating config entries\n");
171 continue;
173 curBlock->entries = ent;
174 ent = curBlock->entries + curBlock->entryCount;
175 curBlock->entryCount++;
177 ent->key = strdup(buffer);
178 ent->value = NULL;
181 /* Look for the end of the line (Null term, new-line, or #-symbol) and
182 eat up the trailing whitespace */
183 memmove(buffer, buffer+i, strlen(buffer+i)+1);
185 i = 0;
186 while(buffer[i] && buffer[i] != '#' && buffer[i] != '\n')
187 i++;
188 do {
189 i--;
190 } while(isspace(buffer[i]));
191 buffer[++i] = 0;
193 free(ent->value);
194 ent->value = strdup(buffer);
196 // AL_PRINT("found '%s' = '%s'\n", ent->key, ent->value);
200 void ReadALConfig(void)
202 FILE *f;
204 cfgBlocks = calloc(1, sizeof(ConfigBlock));
205 cfgBlocks->name = strdup("general");
206 cfgCount = 1;
208 #ifdef _WIN32
209 if(SHGetSpecialFolderPathA(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
211 int p = strlen(buffer);
212 snprintf(buffer+p, sizeof(buffer)-p, "\\alsoft.ini");
213 f = fopen(buffer, "rt");
214 if(f)
216 LoadConfigFromFile(f);
217 fclose(f);
220 #else
221 f = fopen("/etc/openal/alsoft.conf", "r");
222 if(!f)
224 f = fopen("/etc/openal/config", "r");
225 if(f)
226 AL_PRINT("Reading /etc/openal/config; this file is deprecated\n"
227 "\tPlease rename it to /etc/openal/alsoft.conf\n");
229 if(f)
231 LoadConfigFromFile(f);
232 fclose(f);
234 if(getenv("HOME") && *(getenv("HOME")))
236 snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", getenv("HOME"));
237 f = fopen(buffer, "r");
238 if(!f)
240 snprintf(buffer, sizeof(buffer), "%s/.openalrc", getenv("HOME"));
241 f = fopen(buffer, "r");
242 if(f)
243 AL_PRINT("Reading ~/.openalrc; this file is deprecated\n"
244 "\tPlease rename it to ~/.alsoftrc\n");
246 if(f)
248 LoadConfigFromFile(f);
249 fclose(f);
252 #endif
255 void FreeALConfig(void)
257 size_t i;
259 for(i = 0;i < cfgCount;i++)
261 size_t j;
262 for(j = 0;j < cfgBlocks[i].entryCount;j++)
264 free(cfgBlocks[i].entries[j].key);
265 free(cfgBlocks[i].entries[j].value);
267 free(cfgBlocks[i].entries);
268 free(cfgBlocks[i].name);
270 free(cfgBlocks);
271 cfgBlocks = NULL;
272 cfgCount = 0;
275 const char *GetConfigValue(const char *blockName, const char *keyName, const char *def)
277 size_t i, j;
279 if(keyName)
281 if(!blockName)
282 blockName = "general";
284 for(i = 0;i < cfgCount;i++)
286 if(strcasecmp(cfgBlocks[i].name, blockName) != 0)
287 continue;
289 for(j = 0;j < cfgBlocks[i].entryCount;j++)
291 if(strcasecmp(cfgBlocks[i].entries[j].key, keyName) == 0)
292 return cfgBlocks[i].entries[j].value;
297 return def;
300 int GetConfigValueInt(const char *blockName, const char *keyName, int def)
302 const char *val = GetConfigValue(blockName, keyName, "");
304 if(!val[0]) return def;
305 return strtol(val, NULL, 0);
308 float GetConfigValueFloat(const char *blockName, const char *keyName, float def)
310 const char *val = GetConfigValue(blockName, keyName, "");
312 if(!val[0]) return def;
313 #ifdef HAVE_STRTOF
314 return strtof(val, NULL);
315 #else
316 return (float)strtod(val, NULL);
317 #endif