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