rlm@0: /** rlm@0: * OpenAL cross platform audio library rlm@0: * Copyright (C) 1999-2007 by authors. rlm@0: * This library is free software; you can redistribute it and/or rlm@0: * modify it under the terms of the GNU Library General Public rlm@0: * License as published by the Free Software Foundation; either rlm@0: * version 2 of the License, or (at your option) any later version. rlm@0: * rlm@0: * This library is distributed in the hope that it will be useful, rlm@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of rlm@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU rlm@0: * Library General Public License for more details. rlm@0: * rlm@0: * You should have received a copy of the GNU Library General Public rlm@0: * License along with this library; if not, write to the rlm@0: * Free Software Foundation, Inc., 59 Temple Place - Suite 330, rlm@0: * Boston, MA 02111-1307, USA. rlm@0: * Or go to http://www.gnu.org/copyleft/lgpl.html rlm@0: */ rlm@0: rlm@0: #ifdef _WIN32 rlm@0: #ifdef __MINGW64__ rlm@0: #define _WIN32_IE 0x501 rlm@0: #else rlm@0: #define _WIN32_IE 0x400 rlm@0: #endif rlm@0: #endif rlm@0: rlm@0: #include "config.h" rlm@0: rlm@0: #include rlm@0: #include rlm@0: #include rlm@0: #include rlm@0: rlm@0: #include "alMain.h" rlm@0: rlm@0: #ifdef _WIN32_IE rlm@0: #include rlm@0: #endif rlm@0: rlm@0: typedef struct ConfigEntry { rlm@0: char *key; rlm@0: char *value; rlm@0: } ConfigEntry; rlm@0: rlm@0: typedef struct ConfigBlock { rlm@0: char *name; rlm@0: ConfigEntry *entries; rlm@0: size_t entryCount; rlm@0: } ConfigBlock; rlm@0: rlm@0: static ConfigBlock *cfgBlocks; rlm@0: static size_t cfgCount; rlm@0: rlm@0: static char buffer[1024]; rlm@0: rlm@0: static void LoadConfigFromFile(FILE *f) rlm@0: { rlm@0: ConfigBlock *curBlock = cfgBlocks; rlm@0: ConfigEntry *ent; rlm@0: rlm@0: while(fgets(buffer, sizeof(buffer), f)) rlm@0: { rlm@0: size_t i = 0; rlm@0: rlm@0: while(isspace(buffer[i])) rlm@0: i++; rlm@0: if(!buffer[i] || buffer[i] == '#') rlm@0: continue; rlm@0: rlm@0: memmove(buffer, buffer+i, strlen(buffer+i)+1); rlm@0: rlm@0: if(buffer[0] == '[') rlm@0: { rlm@0: ConfigBlock *nextBlock; rlm@0: rlm@0: i = 1; rlm@0: while(buffer[i] && buffer[i] != ']') rlm@0: i++; rlm@0: rlm@0: if(!buffer[i]) rlm@0: { rlm@0: ERR("config parse error: bad line \"%s\"\n", buffer); rlm@0: continue; rlm@0: } rlm@0: buffer[i] = 0; rlm@0: rlm@0: do { rlm@0: i++; rlm@0: if(buffer[i] && !isspace(buffer[i])) rlm@0: { rlm@0: if(buffer[i] != '#') rlm@0: WARN("config warning: extra data after block: \"%s\"\n", buffer+i); rlm@0: break; rlm@0: } rlm@0: } while(buffer[i]); rlm@0: rlm@0: nextBlock = NULL; rlm@0: for(i = 0;i < cfgCount;i++) rlm@0: { rlm@0: if(strcasecmp(cfgBlocks[i].name, buffer+1) == 0) rlm@0: { rlm@0: nextBlock = cfgBlocks+i; rlm@0: TRACE("found block '%s'\n", nextBlock->name); rlm@0: break; rlm@0: } rlm@0: } rlm@0: rlm@0: if(!nextBlock) rlm@0: { rlm@0: nextBlock = realloc(cfgBlocks, (cfgCount+1)*sizeof(ConfigBlock)); rlm@0: if(!nextBlock) rlm@0: { rlm@0: ERR("config parse error: error reallocating config blocks\n"); rlm@0: continue; rlm@0: } rlm@0: cfgBlocks = nextBlock; rlm@0: nextBlock = cfgBlocks+cfgCount; rlm@0: cfgCount++; rlm@0: rlm@0: nextBlock->name = strdup(buffer+1); rlm@0: nextBlock->entries = NULL; rlm@0: nextBlock->entryCount = 0; rlm@0: rlm@0: TRACE("found new block '%s'\n", nextBlock->name); rlm@0: } rlm@0: curBlock = nextBlock; rlm@0: continue; rlm@0: } rlm@0: rlm@0: /* Look for the option name */ rlm@0: i = 0; rlm@0: while(buffer[i] && buffer[i] != '#' && buffer[i] != '=' && rlm@0: !isspace(buffer[i])) rlm@0: i++; rlm@0: rlm@0: if(!buffer[i] || buffer[i] == '#' || i == 0) rlm@0: { rlm@0: ERR("config parse error: malformed option line: \"%s\"\n", buffer); rlm@0: continue; rlm@0: } rlm@0: rlm@0: /* Seperate the option */ rlm@0: if(buffer[i] != '=') rlm@0: { rlm@0: buffer[i++] = 0; rlm@0: rlm@0: while(isspace(buffer[i])) rlm@0: i++; rlm@0: if(buffer[i] != '=') rlm@0: { rlm@0: ERR("config parse error: option without a value: \"%s\"\n", buffer); rlm@0: continue; rlm@0: } rlm@0: } rlm@0: /* Find the start of the value */ rlm@0: buffer[i++] = 0; rlm@0: while(isspace(buffer[i])) rlm@0: i++; rlm@0: rlm@0: /* Check if we already have this option set */ rlm@0: ent = curBlock->entries; rlm@0: while((size_t)(ent-curBlock->entries) < curBlock->entryCount) rlm@0: { rlm@0: if(strcasecmp(ent->key, buffer) == 0) rlm@0: break; rlm@0: ent++; rlm@0: } rlm@0: rlm@0: if((size_t)(ent-curBlock->entries) >= curBlock->entryCount) rlm@0: { rlm@0: /* Allocate a new option entry */ rlm@0: ent = realloc(curBlock->entries, (curBlock->entryCount+1)*sizeof(ConfigEntry)); rlm@0: if(!ent) rlm@0: { rlm@0: ERR("config parse error: error reallocating config entries\n"); rlm@0: continue; rlm@0: } rlm@0: curBlock->entries = ent; rlm@0: ent = curBlock->entries + curBlock->entryCount; rlm@0: curBlock->entryCount++; rlm@0: rlm@0: ent->key = strdup(buffer); rlm@0: ent->value = NULL; rlm@0: } rlm@0: rlm@0: /* Look for the end of the line (Null term, new-line, or #-symbol) and rlm@0: eat up the trailing whitespace */ rlm@0: memmove(buffer, buffer+i, strlen(buffer+i)+1); rlm@0: rlm@0: i = 0; rlm@0: while(buffer[i] && buffer[i] != '#' && buffer[i] != '\n') rlm@0: i++; rlm@0: do { rlm@0: i--; rlm@0: } while(isspace(buffer[i])); rlm@0: buffer[++i] = 0; rlm@0: rlm@0: free(ent->value); rlm@0: ent->value = strdup(buffer); rlm@0: rlm@0: TRACE("found '%s' = '%s'\n", ent->key, ent->value); rlm@0: } rlm@0: } rlm@0: rlm@0: void ReadALConfig(void) rlm@0: { rlm@0: const char *str; rlm@0: FILE *f; rlm@0: rlm@0: cfgBlocks = calloc(1, sizeof(ConfigBlock)); rlm@0: cfgBlocks->name = strdup("general"); rlm@0: cfgCount = 1; rlm@0: rlm@0: #ifdef _WIN32 rlm@0: if(SHGetSpecialFolderPathA(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE) rlm@0: { rlm@0: size_t p = strlen(buffer); rlm@0: snprintf(buffer+p, sizeof(buffer)-p, "\\alsoft.ini"); rlm@0: f = fopen(buffer, "rt"); rlm@0: if(f) rlm@0: { rlm@0: LoadConfigFromFile(f); rlm@0: fclose(f); rlm@0: } rlm@0: } rlm@0: #else rlm@0: f = fopen("/etc/openal/alsoft.conf", "r"); rlm@0: if(f) rlm@0: { rlm@0: LoadConfigFromFile(f); rlm@0: fclose(f); rlm@0: } rlm@0: if((str=getenv("HOME")) != NULL && *str) rlm@0: { rlm@0: snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", str); rlm@0: f = fopen(buffer, "r"); rlm@0: if(f) rlm@0: { rlm@0: LoadConfigFromFile(f); rlm@0: fclose(f); rlm@0: } rlm@0: } rlm@0: #endif rlm@0: if((str=getenv("ALSOFT_CONF")) != NULL && *str) rlm@0: { rlm@0: f = fopen(str, "r"); rlm@0: if(f) rlm@0: { rlm@0: LoadConfigFromFile(f); rlm@0: fclose(f); rlm@0: } rlm@0: } rlm@0: } rlm@0: rlm@0: void FreeALConfig(void) rlm@0: { rlm@0: size_t i; rlm@0: rlm@0: for(i = 0;i < cfgCount;i++) rlm@0: { rlm@0: size_t j; rlm@0: for(j = 0;j < cfgBlocks[i].entryCount;j++) rlm@0: { rlm@0: free(cfgBlocks[i].entries[j].key); rlm@0: free(cfgBlocks[i].entries[j].value); rlm@0: } rlm@0: free(cfgBlocks[i].entries); rlm@0: free(cfgBlocks[i].name); rlm@0: } rlm@0: free(cfgBlocks); rlm@0: cfgBlocks = NULL; rlm@0: cfgCount = 0; rlm@0: } rlm@0: rlm@0: const char *GetConfigValue(const char *blockName, const char *keyName, const char *def) rlm@0: { rlm@0: size_t i, j; rlm@0: rlm@0: if(!keyName) rlm@0: return def; rlm@0: rlm@0: if(!blockName) rlm@0: blockName = "general"; rlm@0: rlm@0: for(i = 0;i < cfgCount;i++) rlm@0: { rlm@0: if(strcasecmp(cfgBlocks[i].name, blockName) != 0) rlm@0: continue; rlm@0: rlm@0: for(j = 0;j < cfgBlocks[i].entryCount;j++) rlm@0: { rlm@0: if(strcasecmp(cfgBlocks[i].entries[j].key, keyName) == 0) rlm@0: { rlm@0: TRACE("Found %s:%s = \"%s\"\n", blockName, keyName, rlm@0: cfgBlocks[i].entries[j].value); rlm@0: if(cfgBlocks[i].entries[j].value[0]) rlm@0: return cfgBlocks[i].entries[j].value; rlm@0: return def; rlm@0: } rlm@0: } rlm@0: } rlm@0: rlm@0: TRACE("Key %s:%s not found\n", blockName, keyName); rlm@0: return def; rlm@0: } rlm@0: rlm@0: int ConfigValueExists(const char *blockName, const char *keyName) rlm@0: { rlm@0: const char *val = GetConfigValue(blockName, keyName, ""); rlm@0: return !!val[0]; rlm@0: } rlm@0: rlm@0: int GetConfigValueInt(const char *blockName, const char *keyName, int def) rlm@0: { rlm@0: const char *val = GetConfigValue(blockName, keyName, ""); rlm@0: rlm@0: if(!val[0]) return def; rlm@0: return strtol(val, NULL, 0); rlm@0: } rlm@0: rlm@0: float GetConfigValueFloat(const char *blockName, const char *keyName, float def) rlm@0: { rlm@0: const char *val = GetConfigValue(blockName, keyName, ""); rlm@0: rlm@0: if(!val[0]) return def; rlm@0: #ifdef HAVE_STRTOF rlm@0: return strtof(val, NULL); rlm@0: #else rlm@0: return (float)strtod(val, NULL); rlm@0: #endif rlm@0: } rlm@0: rlm@0: int GetConfigValueBool(const char *blockName, const char *keyName, int def) rlm@0: { rlm@0: const char *val = GetConfigValue(blockName, keyName, ""); rlm@0: rlm@0: if(!val[0]) return !!def; rlm@0: return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || rlm@0: strcasecmp(val, "on") == 0 || atoi(val) != 0); rlm@0: }