aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--doc/mpdconf.example66
-rw-r--r--src/audio.c107
-rw-r--r--src/audioOutput.c40
-rw-r--r--src/audioOutput.h8
-rw-r--r--src/audioOutput_ao.c41
-rw-r--r--src/audioOutput_shout.c84
-rw-r--r--src/conf.c566
-rw-r--r--src/conf.h111
-rw-r--r--src/directory.c3
-rw-r--r--src/inputStream_http.c108
-rw-r--r--src/interface.c81
-rw-r--r--src/list.c2
-rw-r--r--src/list.h1
-rw-r--r--src/listen.c20
-rw-r--r--src/log.c16
-rw-r--r--src/main.c35
-rw-r--r--src/path.c9
-rw-r--r--src/permission.c57
-rw-r--r--src/playerData.c40
-rw-r--r--src/playlist.c54
-rw-r--r--src/replayGain.c26
-rw-r--r--src/tag.c12
-rw-r--r--src/volume.c85
24 files changed, 948 insertions, 626 deletions
diff --git a/TODO b/TODO
index bd3662635..28bfdc80e 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,7 @@
0.12
----
+*) Fix id3v1 encoding
+
*) Abstract audio stuff into a plugin oriented thing
*) audio_ao & audio_oss & audio_shout
*) allow for sending to multiple audio devices
diff --git a/doc/mpdconf.example b/doc/mpdconf.example
index 76c652e64..f13cf2912 100644
--- a/doc/mpdconf.example
+++ b/doc/mpdconf.example
@@ -71,28 +71,25 @@ error_file "~/.mpd/mpd.error"
################## AUDIO OUTPUT ##########################
#
# libao (ao_driver) supports any of the following:
-#
-# * Null output (handy for testing without a sound device)
-# * WAV files
-# * AU files
-# * OSS (Open Sound System, used on Linux and FreeBSD)
-# * aRts
-# * esd (ESounD or Enlighten Sound Daemon)
-# * ALSA (Advanced Linux Sound Architecture)
-# * AIX
-# * Sun/NetBSD/OpenBSD
-# * IRIX
-# * NAS (Network Audio Server)
-#
# Refer to libao documentation for more information
#
# OSS Audio Output
-#ao_driver "oss"
-#ao_driver_options "dsp=/dev/dsp"
+#audio_output {
+# type "ao"
+# name "my OSS device"
+# driver "oss"
+# options "dsp=/dev/dsp"
+# write_size "1024"
+#}
#
# ALSA Audio Output
-#ao_driver "alsa09"
-#ao_driver_options "dev=hw:0,0"
+#audio_output {
+# type "ao"
+# name "my ALSA device"
+# driver "alsa09"
+# options "dev=hw:0,0"
+# write_size "1024"
+#}
#
# Set this if you have problems
# playing audio files.
@@ -101,11 +98,24 @@ error_file "~/.mpd/mpd.error"
#
#audio_output_format "44100:16:2"
#
-# You should not need mess with
-# this value unless you know
-# what you're doing.
+##########################################################
+
+
+################# SHOUT STREAMING ########################
+#
+# Set this to allow mpd to stream its output to icecast2
+# (i.e. mpd is a icecast2 source)
#
-#audio_write_size "1024"
+#audio_output {
+# type "shout"
+# name "my cool stream"
+# host "hostname"
+# port "8000"
+# user "source"
+# password "hackme"
+# quality "5.0"
+# format "44100:16:1"
+#}
#
##########################################################
@@ -179,20 +189,6 @@ error_file "~/.mpd/mpd.error"
##########################################
-################ SHOUT OPTIONS #####################
-#
-#shout_host "host"
-#shout_port "8000"
-#shout_user "source"
-#shout_password "hackme"
-#shout_name "My MPD!"
-#shout_mount "/mpd.ogg"
-#shout_quality "0.5"
-#shout_format "44100:16:1"
-#
-####################################################
-
-
################ MISCELLANEOUS OPTIONS ###################
#
# This setting exists as precaution against attacks.
diff --git a/src/audio.c b/src/audio.c
index 653fb55f5..e3a311abb 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -31,9 +31,6 @@ static AudioFormat audio_format;
static AudioFormat * audio_configFormat = NULL;
-static AudioOutput * aoOutput = NULL;
-static AudioOutput * shoutOutput = NULL;
-
void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
if(!src) return;
@@ -42,17 +39,34 @@ void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
dest->channels = src->channels;
}
+static AudioOutput ** audioOutputArray = NULL;
+static int audioOutputArraySize = 0;
+
extern AudioOutputPlugin aoPlugin;
extern AudioOutputPlugin shoutPlugin;
void initAudioDriver() {
+ ConfigParam * param = NULL;
+ int i;
+
initAudioOutputPlugins();
loadAudioOutputPlugin(&aoPlugin);
loadAudioOutputPlugin(&shoutPlugin);
- aoOutput = newAudioOutput("ao");
- assert(aoOutput);
- shoutOutput = newAudioOutput("shout");
+ while((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param))) {
+ i = audioOutputArraySize++;
+
+ audioOutputArray = realloc(audioOutputArray,
+ audioOutputArraySize*sizeof(AudioOutput *));
+
+ audioOutputArray[i] = newAudioOutput(param);
+
+ if(!audioOutputArray[i]) {
+ ERROR("problems configuring output device defined at "
+ "line %i\n", param->line);
+ exit(EXIT_FAILURE);
+ }
+ }
}
void getOutputAudioFormat(AudioFormat * inAudioFormat,
@@ -65,13 +79,17 @@ void getOutputAudioFormat(AudioFormat * inAudioFormat,
}
void initAudioConfig() {
- char * conf = getConf()[CONF_AUDIO_OUTPUT_FORMAT];
+ ConfigParam * param = getConfigParam(CONF_AUDIO_OUTPUT_FORMAT);
- if(NULL == conf) return;
+ if(NULL == param || NULL == param->value) return;
audio_configFormat = malloc(sizeof(AudioFormat));
- if(0 != parseAudioConfig(audio_configFormat, conf)) exit(EXIT_FAILURE);
+ if(0 != parseAudioConfig(audio_configFormat, param->value)) {
+ ERROR("error parsing \"%s\" at line %i\n",
+ CONF_AUDIO_OUTPUT_FORMAT, param->line);
+ exit(EXIT_FAILURE);
+ }
}
int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
@@ -145,10 +163,15 @@ void finishAudioConfig() {
}
void finishAudioDriver() {
- finishAudioOutput(aoOutput);
- if(shoutOutput) finishAudioOutput(shoutOutput);
- shoutOutput = NULL;
- aoOutput = NULL;
+ int i;
+
+ for(i = 0; i < audioOutputArraySize; i++) {
+ finishAudioOutput(audioOutputArray[i]);
+ }
+
+ free(audioOutputArray);
+ audioOutputArray = NULL;
+ audioOutputArraySize = 0;
}
int isCurrentAudioFormat(AudioFormat * audioFormat) {
@@ -160,29 +183,65 @@ int isCurrentAudioFormat(AudioFormat * audioFormat) {
}
int openAudioDevice(AudioFormat * audioFormat) {
- if(!aoOutput->open || !isCurrentAudioFormat(audioFormat)) {
- if(audioFormat) copyAudioFormat(&audio_format, audioFormat);
- if(shoutOutput) openAudioOutput(shoutOutput, &audio_format);
- return openAudioOutput(aoOutput, &audio_format);
+ int isCurrentFormat = isCurrentAudioFormat(audioFormat);
+ int ret = -1;
+ int i;
+
+ if(!audioOutputArray) return -1;
+
+ if(!isCurrentFormat) {
+ copyAudioFormat(&audio_format, audioFormat);
}
- return 0;
+ for(i = 0; i < audioOutputArraySize; i++) {
+ if(!audioOutputArray[i]->open || !isCurrentFormat) {
+ if(0 == openAudioOutput(audioOutputArray[i],
+ &audio_format))
+ {
+ ret = 0;
+ }
+ }
+ }
+
+ return ret;
}
int playAudio(char * playChunk, int size) {
- if(shoutOutput) playAudioOutput(shoutOutput, playChunk, size);
- return playAudioOutput(aoOutput, playChunk, size);
+ int ret = -1;
+ int i;
+
+ for(i = 0; i < audioOutputArraySize; i++) {
+ if(0 == playAudioOutput(audioOutputArray[i], playChunk, size)) {
+ ret = 0;
+ }
+ }
+
+ return ret;
}
int isAudioDeviceOpen() {
- return aoOutput->open;
+ int ret = 0;
+ int i;
+
+ for(i = 0; i < audioOutputArraySize; i++) {
+ ret |= audioOutputArray[i]->open;
+ }
+
+ return ret;
}
void closeAudioDevice() {
- if(shoutOutput) closeAudioOutput(shoutOutput);
- closeAudioOutput(aoOutput);
+ int i;
+
+ for(i = 0; i < audioOutputArraySize; i++) {
+ closeAudioOutput(audioOutputArray[i]);
+ }
}
void sendMetadataToAudioDevice(MpdTag * tag) {
- if(shoutOutput) sendMetadataToAudioOutput(shoutOutput, tag);
+ int i;
+
+ for(i = 0; i < audioOutputArraySize; i++) {
+ sendMetadataToAudioOutput(audioOutputArray[i], tag);
+ }
}
diff --git a/src/audioOutput.c b/src/audioOutput.c
index d85b9d978..0175ed04f 100644
--- a/src/audioOutput.c
+++ b/src/audioOutput.c
@@ -1,6 +1,12 @@
-#include <audioOutput.h>
+#include "audioOutput.h"
-#include <list.h>
+#include "list.h"
+#include "log.h"
+
+#include <string.h>
+
+#define AUDIO_OUTPUT_TYPE "type"
+#define AUDIO_OUTPUT_NAME "name"
static List * audioOutputPluginList;
@@ -21,13 +27,32 @@ void finishAudioOutputPlugins() {
freeList(audioOutputPluginList);
}
-AudioOutput * newAudioOutput(char * name) {
+#define getBlockParam(name, str) { \
+ BlockParam * bp; \
+ bp = getBlockParam(param, name); \
+ if(bp == NULL) { \
+ ERROR("couldn't find parameter \"%s\" in audio output " \
+ "definition begining at %i\n", \
+ name, param->line); \
+ exit(EXIT_FAILURE); \
+ } \
+ str = bp->value; \
+}
+
+AudioOutput * newAudioOutput(ConfigParam * param) {
AudioOutput * ret = NULL;
void * data = NULL;
+ char * name = NULL;
+ char * type = NULL;
+
+ getBlockParam(AUDIO_OUTPUT_NAME, name);
+ getBlockParam(AUDIO_OUTPUT_TYPE, type);
- if(findInList(audioOutputPluginList, name, &data)) {
+ if(findInList(audioOutputPluginList, type, &data)) {
AudioOutputPlugin * plugin = (AudioOutputPlugin *) data;
ret = malloc(sizeof(AudioOutput));
+ ret->name = strdup(name);
+ ret->type = strdup(type);
ret->finishDriverFunc = plugin->finishDriverFunc;
ret->openDeviceFunc = plugin->openDeviceFunc;
ret->playFunc = plugin->playFunc;
@@ -35,11 +60,16 @@ AudioOutput * newAudioOutput(char * name) {
ret->sendMetdataFunc = plugin->sendMetdataFunc;
ret->open = 0;
- if(plugin->initDriverFunc(ret) != 0) {
+ if(plugin->initDriverFunc(ret, param) != 0) {
free(ret);
ret = NULL;
}
}
+ else {
+ ERROR("couldn't find audio output plugin for type \"%s\" at "
+ "line %i", type, param->line);
+ exit(EXIT_FAILURE);
+ }
return ret;
}
diff --git a/src/audioOutput.h b/src/audioOutput.h
index ec43e9e7c..49c7110f9 100644
--- a/src/audioOutput.h
+++ b/src/audioOutput.h
@@ -24,12 +24,14 @@
#include "mpd_types.h"
#include "audio.h"
#include "tag.h"
+#include "conf.h"
#define AUDIO_AO_DRIVER_DEFAULT "default"
typedef struct _AudioOutput AudioOutput;
-typedef int (* AudioOutputInitDriverFunc) (AudioOutput * audioOutput);
+typedef int (* AudioOutputInitDriverFunc) (AudioOutput * audioOutput,
+ ConfigParam * param);
typedef void (* AudioOutputFinishDriverFunc) (AudioOutput * audioOutput);
@@ -46,6 +48,8 @@ typedef void (* AudioOutputSendMetadataFunc) (AudioOutput * audioOutput,
struct _AudioOutput {
int open;
+ char * name;
+ char * type;
AudioOutputFinishDriverFunc finishDriverFunc;
AudioOutputOpenDeviceFunc openDeviceFunc;
@@ -73,7 +77,7 @@ void finishAudioOutputPlugins();
void loadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
-AudioOutput * newAudioOutput(char * name);
+AudioOutput * newAudioOutput(ConfigParam * param);
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat);
int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size);
void closeAudioOutput(AudioOutput * audioOutput);
diff --git a/src/audioOutput_ao.c b/src/audioOutput_ao.c
index 7c997c99e..60c4ea402 100644
--- a/src/audioOutput_ao.c
+++ b/src/audioOutput_ao.c
@@ -56,7 +56,9 @@ static void audioOutputAo_error() {
}
}
-static int audioOutputAo_initDriver(AudioOutput * audioOutput) {
+static int audioOutputAo_initDriver(AudioOutput * audioOutput,
+ ConfigParam * param)
+{
ao_info * ai;
char * dup;
char * stk1;
@@ -66,38 +68,51 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput) {
char * value;
char * test;
AoData * ad = newAoData();
+ BlockParam * blockParam;
audioOutput->data = ad;
- ad->writeSize = strtol((getConf())[CONF_AUDIO_WRITE_SIZE],&test,10);
- if (*test!='\0') {
- ERROR("\"%s\" is not a valid write size\n",
- (getConf())[CONF_AUDIO_WRITE_SIZE]);
- exit(EXIT_FAILURE);
+ if((blockParam = getBlockParam(param, "write_size"))) {
+ ad->writeSize = strtol(blockParam->value, &test, 10);
+ if (*test!='\0') {
+ ERROR("\"%s\" is not a valid write size at line %i\n",
+ blockParam->value, blockParam->line);
+ exit(EXIT_FAILURE);
+ }
}
+ else ad->writeSize = 1024;
if(driverInitCount == 0) {
ao_initialize();
}
driverInitCount++;
-
- if(strcmp(AUDIO_AO_DRIVER_DEFAULT,(getConf())[CONF_AO_DRIVER])==0) {
+
+ blockParam = getBlockParam(param, "driver");
+
+ if(!blockParam || 0 == strcmp(blockParam->value,"default")) {
ad->driverId = ao_default_driver_id();
}
else if((ad->driverId =
- ao_driver_id((getConf())[CONF_AO_DRIVER]))<0) {
- ERROR("\"%s\" is not a valid ao driver\n",
- (getConf())[CONF_AO_DRIVER]);
+ ao_driver_id(blockParam->value))<0) {
+ ERROR("\"%s\" is not a valid ao driver at line %i\n",
+ blockParam->value, blockParam->line);
exit(EXIT_FAILURE);
}
if((ai = ao_driver_info(ad->driverId))==NULL) {
- ERROR("problems getting ao_driver_info\n");
+ ERROR("problems getting driver info for device defined at "
+ "line %i\n", param->line);
ERROR("you may not have permission to the audio device\n");
exit(EXIT_FAILURE);
}
- dup = strdup((getConf())[CONF_AO_DRIVER_OPTIONS]);
+ blockParam = getBlockParam(param, "options");
+
+ if(blockParam) {
+ dup = strdup(blockParam->value);
+ }
+ else dup = strdup("");
+
if(strlen(dup)) {
stk1 = NULL;
n1 = strtok_r(dup,";",&stk1);
diff --git a/src/audioOutput_shout.c b/src/audioOutput_shout.c
index 45ef00846..f41b57359 100644
--- a/src/audioOutput_shout.c
+++ b/src/audioOutput_shout.c
@@ -88,7 +88,16 @@ static void freeShoutData(ShoutData * sd) {
free(sd);
}
-static int shout_initDriver(AudioOutput * audioOutput) {
+#define checkBlockParam(name) { \
+ blockParam = getBlockParam(param, name); \
+ if(!blockParam) { \
+ ERROR("no \"%s\" defined for shout device defined at line " \
+ "%i\n", name, param->line); \
+ exit(EXIT_FAILURE); \
+ } \
+}
+
+static int shout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
ShoutData * sd;
char * test;
int port;
@@ -97,73 +106,50 @@ static int shout_initDriver(AudioOutput * audioOutput) {
char * passwd;
char * user;
char * name;
-
- if(!getConf()[CONF_SHOUT_HOST]) {
- return -1;
- }
+ BlockParam * blockParam;
sd = newShoutData();
- if(!getConf()[CONF_SHOUT_MOUNT]) {
- ERROR("shout host defined but not shout mount point\n");
- exit(EXIT_FAILURE);
- }
-
- if(!getConf()[CONF_SHOUT_PORT]) {
- ERROR("shout host defined but not shout port\n");
- exit(EXIT_FAILURE);
- }
+ checkBlockParam("host");
+ host = blockParam->value;
- if(!getConf()[CONF_SHOUT_PASSWD]) {
- ERROR("shout host defined but not shout password\n");
- exit(EXIT_FAILURE);
- }
+ checkBlockParam("mount");
+ mount = blockParam->value;
- if(!getConf()[CONF_SHOUT_NAME]) {
- ERROR("shout host defined but not shout name\n");
- exit(EXIT_FAILURE);
- }
+ checkBlockParam("port");
- if(!getConf()[CONF_SHOUT_USER]) {
- ERROR("shout host defined but not shout user\n");
- exit(EXIT_FAILURE);
- }
+ port = strtol(blockParam->value, &test, 10);
- if(!getConf()[CONF_SHOUT_QUALITY]) {
- ERROR("shout host defined but not shout quality\n");
+ if(*test != '\0' || port <= 0) {
+ ERROR("shout port \"%s\" is not a positive integer, line %i\n",
+ blockParam->value, blockParam->line);
exit(EXIT_FAILURE);
}
- if(!getConf()[CONF_SHOUT_FORMAT]) {
- ERROR("shout host defined but not shout format\n");
- exit(EXIT_FAILURE);
- }
+ checkBlockParam("password");
+ passwd = blockParam->value;
- host = getConf()[CONF_SHOUT_HOST];
- passwd = getConf()[CONF_SHOUT_PASSWD];
- user = getConf()[CONF_SHOUT_USER];
- mount = getConf()[CONF_SHOUT_MOUNT];
- name = getConf()[CONF_SHOUT_NAME];
+ checkBlockParam("name");
+ name = blockParam->value;
- port = strtol(getConf()[CONF_SHOUT_PORT], &test, 10);
+ checkBlockParam("user");
+ user = blockParam->value;
- if(*test != '\0' || port <= 0) {
- ERROR("shout port \"%s\" is not a positive integer\n",
- getConf()[CONF_SHOUT_PORT]);
- exit(EXIT_FAILURE);
- }
+ checkBlockParam("quality");
- sd->quality = strtod(getConf()[CONF_SHOUT_QUALITY], &test);
+ sd->quality = strtod(blockParam->value, &test);
if(*test != '\0' || sd->quality < 0.0 || sd->quality > 10.0) {
ERROR("shout quality \"%s\" is not a number in the range "
- "0-10\n", getConf()[CONF_SHOUT_QUALITY]);
+ "0-10, line %i\n", blockParam->value,
+ blockParam->line);
exit(EXIT_FAILURE);
}
- if(0 != parseAudioConfig(&(sd->outAudioFormat),
- getConf()[CONF_SHOUT_FORMAT]) )
- {
+ checkBlockParam("format");
+
+ if(0 != parseAudioConfig(&(sd->outAudioFormat), blockParam->value)) {
+ ERROR("error parsing format at line %i\n", blockParam->line);
exit(EXIT_FAILURE);
}
@@ -276,7 +262,7 @@ static int initEncoder(ShoutData * sd) {
vorbis_info_init(&(sd->vi));
if( 0 != vorbis_encode_init_vbr(&(sd->vi), sd->outAudioFormat.channels,
- sd->outAudioFormat.sampleRate, sd->quality) )
+ sd->outAudioFormat.sampleRate, sd->quality/10.0) )
{
ERROR("problem seting up vorbis encoder for shout\n");
vorbis_info_clear(&(sd->vi));
diff --git a/src/conf.c b/src/conf.c
index a89a1e334..ccbb99f1c 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -22,8 +22,7 @@
#include "utils.h"
#include "buffer2array.h"
-#include "audio.h"
-#include "volume.h"
+#include "list.h"
#include <sys/param.h>
#include <stdio.h>
@@ -35,270 +34,385 @@
#define MAX_STRING_SIZE MAXPATHLEN+80
-#define CONF_COMMENT '#'
-
-#define CONF_NUMBER_OF_PARAMS 43
-#define CONF_NUMBER_OF_PATHS 6
-#define CONF_NUMBER_OF_REQUIRED 5
-#define CONF_NUMBER_OF_ALLOW_CATS 1
-
-#define CONF_CONNECTION_TIMEOUT_DEFAULT "60"
-#define CONF_MAX_CONNECTIONS_DEFAULT "5"
-#define CONF_MAX_PLAYLIST_LENGTH_DEFAULT "16384"
-#define CONF_BUFFER_BEFORE_PLAY_DEFAULT "25%"
-#define CONF_MAX_COMMAND_LIST_SIZE_DEFAULT "2048"
-#define CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT "2048"
-#define CONF_AO_DRIVER_DEFAULT AUDIO_AO_DRIVER_DEFAULT
-#define CONF_AO_DRIVER_OPTIONS_DEFAULT ""
-#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT "no"
-#define CONF_BIND_TO_ADDRESS_DEFAULT "any"
-#define CONF_USER_DEFAULT ""
-#define CONF_LOG_LEVEL_DEFAULT "default"
-#define CONF_AUDIO_WRITE_SIZE_DEFAULT "1024"
-#define CONF_BUFFER_SIZE_DEFAULT "2048"
-#ifndef NO_OSS_MIXER
-#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_OSS
-#define CONF_MIXER_DEVICE_DEFAULT ""
-#else
-#ifdef HAVE_ALSA
-#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_ALSA
-#define CONF_MIXER_DEVICE_DEFAULT ""
-#else
-#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_SOFTWARE
-#define CONF_MIXER_DEVICE_DEFAULT ""
-#endif
-#endif
-
-static char * conf_params[CONF_NUMBER_OF_PARAMS];
+#define CONF_COMMENT '#'
+#define CONF_BLOCK_BEGIN "{"
+#define CONF_BLOCK_END "}"
-void initConf() {
+#define CONF_REPEATABLE_MASK 0x01
+#define CONF_BLOCK_MASK 0x02
+
+typedef struct _configEntry {
+ unsigned char mask;
+ List * configParamList;
+} ConfigEntry;
+
+static List * configEntriesList = NULL;
+
+static ConfigParam * newConfigParam(char * value, int line) {
+ ConfigParam * ret = malloc(sizeof(ConfigParam));
+
+ if(!value) ret->value = NULL;
+ else ret->value = strdup(value);
+
+ ret->line = line;
+
+ ret->numberOfBlockParams = 0;
+ ret->blockParams = NULL;
+
+ return ret;
+}
+
+static void freeConfigParam(ConfigParam * param) {
int i;
- for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) conf_params[i] = NULL;
-
- /* we don't specify these on the command line */
- conf_params[CONF_CONNECTION_TIMEOUT] = strdup(CONF_CONNECTION_TIMEOUT_DEFAULT);
- conf_params[CONF_MIXER_DEVICE] = strdup(CONF_MIXER_DEVICE_DEFAULT);
- conf_params[CONF_MAX_CONNECTIONS] = strdup(CONF_MAX_CONNECTIONS_DEFAULT);
- conf_params[CONF_MAX_PLAYLIST_LENGTH] = strdup(CONF_MAX_PLAYLIST_LENGTH_DEFAULT);
- conf_params[CONF_BUFFER_BEFORE_PLAY] = strdup(CONF_BUFFER_BEFORE_PLAY_DEFAULT);
- conf_params[CONF_MAX_COMMAND_LIST_SIZE] = strdup(CONF_MAX_COMMAND_LIST_SIZE_DEFAULT);
- conf_params[CONF_MAX_OUTPUT_BUFFER_SIZE] = strdup(CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT);
- conf_params[CONF_AO_DRIVER] = strdup(CONF_AO_DRIVER_DEFAULT);
- conf_params[CONF_AO_DRIVER_OPTIONS] = strdup(CONF_AO_DRIVER_OPTIONS_DEFAULT);
- conf_params[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS] = strdup(CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT);
- conf_params[CONF_BIND_TO_ADDRESS] = strdup(CONF_BIND_TO_ADDRESS_DEFAULT);
- conf_params[CONF_MIXER_TYPE] = strdup(CONF_MIXER_TYPE_DEFAULT);
- conf_params[CONF_USER] = strdup(CONF_USER_DEFAULT);
- conf_params[CONF_LOG_LEVEL] = strdup(CONF_LOG_LEVEL_DEFAULT);
- conf_params[CONF_AUDIO_WRITE_SIZE] = strdup(CONF_AUDIO_WRITE_SIZE_DEFAULT);
- conf_params[CONF_BUFFER_SIZE] = strdup(CONF_BUFFER_SIZE_DEFAULT);
+ if(param->value) free(param->value);
+
+ for(i=0; i<param->numberOfBlockParams; i++) {
+ if(param->blockParams[i].name) {
+ free(param->blockParams[i].name);
+ }
+ if(param->blockParams[i].value) {
+ free(param->blockParams[i].value);
+ }
+ }
+
+ if(param->numberOfBlockParams) free(param->blockParams);
+
+ free(param);
}
-char ** readConf(char * file) {
- char * conf_strings[CONF_NUMBER_OF_PARAMS] = {
- "port",
- "music_directory",
- "playlist_directory",
- "log_file",
- "error_file",
- "connection_timeout",
- "mixer_device",
- "max_connections",
- "max_playlist_length",
- "buffer_before_play",
- "max_command_list_size",
- "max_output_buffer_size",
- "ao_driver",
- "ao_driver_options",
- "save_absolute_paths_in_playlists",
- "bind_to_address",
- "mixer_type",
- "state_file",
- "user",
- "db_file",
- "log_level",
- "mixer_control",
- "audio_write_size",
- "filesystem_charset",
- "password",
- "default_permissions",
- "audio_buffer_size",
- "replaygain",
- "audio_output_format",
- "http_proxy_host",
- "http_proxy_port",
- "http_proxy_user",
- "http_proxy_password",
- "replaygain_preamp",
- "shout_host",
- "shout_port",
- "shout_password",
- "shout_mount",
- "shout_name",
- "shout_user",
- "shout_quality",
- "id3v1_encoding",
- "shout_format"
- };
-
- int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
- CONF_MUSIC_DIRECTORY,
- CONF_PLAYLIST_DIRECTORY,
- CONF_LOG_FILE,
- CONF_ERROR_FILE,
- CONF_STATE_FILE,
- CONF_DB_FILE
- };
-
- int conf_required[CONF_NUMBER_OF_REQUIRED] = {
- CONF_MUSIC_DIRECTORY,
- CONF_PLAYLIST_DIRECTORY,
- CONF_LOG_FILE,
- CONF_ERROR_FILE,
- CONF_PORT
- };
-
- short conf_allowCat[CONF_NUMBER_OF_ALLOW_CATS] = {
- CONF_PASSWORD
- };
+ConfigEntry * newConfigEntry(int repeatable, int block) {
+ ConfigEntry * ret = malloc(sizeof(ConfigEntry));
+ ret->mask = 0;
+ ret->configParamList = makeList((ListFreeDataFunc *)freeConfigParam);
+
+ if(repeatable) ret->mask |= CONF_REPEATABLE_MASK;
+ if(block) ret->mask |= CONF_BLOCK_MASK;
+
+ return ret;
+}
+
+void freeConfigEntry(ConfigEntry * entry) {
+ freeList(entry->configParamList);
+ free(entry);
+}
+
+void registerConfigParam(char * name, int repeatable, int block) {
+ ConfigEntry * entry;
+
+ if(findInList(configEntriesList, name, NULL)) {
+ ERROR("config parameter \"%s\" already registered\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ entry = newConfigEntry(repeatable, block);
+
+ insertInList(configEntriesList, name, entry);
+}
+
+void initConf() {
+ configEntriesList = makeList((ListFreeDataFunc *)freeConfigEntry);
+
+ registerConfigParam(CONF_PORT, 0, 0);
+ registerConfigParam(CONF_MUSIC_DIR, 0, 0);
+ registerConfigParam(CONF_PLAYLIST_DIR, 0, 0);
+ registerConfigParam(CONF_LOG_FILE, 0, 0);
+ registerConfigParam(CONF_ERROR_FILE, 0, 0);
+ registerConfigParam(CONF_CONN_TIMEOUT, 0, 0);
+ registerConfigParam(CONF_MIXER_DEVICE, 0, 0);
+ registerConfigParam(CONF_MAX_CONN, 0, 0);
+ registerConfigParam(CONF_MAX_PLAYLIST_LENGTH, 0, 0);
+ registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0);
+ registerConfigParam(CONF_MAX_COMMAND_LIST_SIZE, 0, 0);
+ registerConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE, 0, 0);
+ registerConfigParam(CONF_AUDIO_OUTPUT, 1, 1);
+ registerConfigParam(CONF_SAVE_ABSOLUTE_PATHS, 0, 0);
+ registerConfigParam(CONF_BIND_TO_ADDRESS, 1, 0);
+ registerConfigParam(CONF_MIXER_TYPE, 0, 0);
+ registerConfigParam(CONF_STATE_FILE, 0, 0);
+ registerConfigParam(CONF_USER, 0, 0);
+ registerConfigParam(CONF_DB_FILE, 0, 0);
+ registerConfigParam(CONF_LOG_LEVEL, 0, 0);
+ registerConfigParam(CONF_MIXER_CONTROL, 0, 0);
+ registerConfigParam(CONF_AUDIO_WRITE_SIZE, 0, 0);
+ registerConfigParam(CONF_FS_CHARSET, 0, 0);
+ registerConfigParam(CONF_PASSWORD, 1, 0);
+ registerConfigParam(CONF_DEFAULT_PERMS, 0, 0);
+ registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0);
+ registerConfigParam(CONF_REPLAYGAIN, 0, 0);
+ registerConfigParam(CONF_AUDIO_OUTPUT_FORMAT, 0, 0);
+ registerConfigParam(CONF_HTTP_PROXY_HOST, 0, 0);
+ registerConfigParam(CONF_HTTP_PROXY_PORT, 0, 0);
+ registerConfigParam(CONF_HTTP_PROXY_USER, 0, 0);
+ registerConfigParam(CONF_HTTP_PROXY_PASSWORD, 0, 0);
+ registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0);
+ registerConfigParam(CONF_ID3V1_ENCODING, 0, 0);
+}
+
+static void addBlockParam(ConfigParam * param, char * name, char * value,
+ int line)
+{
+ param->numberOfBlockParams++;
+
+ param->blockParams = realloc(param->blockParams,
+ param->numberOfBlockParams*sizeof(BlockParam));
+
+ param->blockParams[param->numberOfBlockParams-1].name = strdup(name);
+ param->blockParams[param->numberOfBlockParams-1].value = strdup(value);
+ param->blockParams[param->numberOfBlockParams-1].line = line;
+}
+
+static ConfigParam * readConfigBlock(FILE * fp, int * count, char * string) {
+ ConfigParam * ret = newConfigParam(NULL, *count);
+
+ char ** array;
+ int i;
+ int numberOfArgs;
+ int argsMinusComment;
+
+ while(myFgets(string, MAX_STRING_SIZE ,fp)) {
+ (*count)++;
+
+ numberOfArgs = buffer2array(string, &array);
+
+ for(i=0; i<numberOfArgs; i++) {
+ if(array[i][0] == CONF_COMMENT) break;
+ }
+
+ argsMinusComment = i;
+
+ if(0 == argsMinusComment) continue;
+
+ if(1 == argsMinusComment &&
+ 0 == strcmp(array[0], CONF_BLOCK_END))
+ {
+ break;
+ }
+
+ if(2 != argsMinusComment) {
+ ERROR("improperly formated config file at line %i:"
+ " %s\n", count, string);
+ exit(EXIT_FAILURE);
+ }
+
+ if(0 == strcmp(array[0], CONF_BLOCK_BEGIN) ||
+ 0 == strcmp(array[1], CONF_BLOCK_BEGIN) ||
+ 0 == strcmp(array[0], CONF_BLOCK_END) ||
+ 0 == strcmp(array[1], CONF_BLOCK_END))
+ {
+ ERROR("improperly formated config file at line %i:"
+ " %s\n", count, string);
+ ERROR("in block begging at line %i\n", ret->line);
+ exit(EXIT_FAILURE);
+ }
+
+ addBlockParam(ret, array[0], array[1], *count);
+
+ freeArgArray(array, numberOfArgs);
+ }
+
+ return ret;
+}
+
+void readConf(char * file) {
FILE * fp;
char string[MAX_STRING_SIZE+1];
char ** array;
int i;
int numberOfArgs;
- short allowCat[CONF_NUMBER_OF_PARAMS];
+ int argsMinusComment;
int count = 0;
-
- for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) allowCat[i] = 0;
-
- for(i=0;i<CONF_NUMBER_OF_ALLOW_CATS;i++) allowCat[conf_allowCat[i]] = 1;
+ ConfigEntry * entry;
+ void * voidPtr;
+ ConfigParam * param;
if(!(fp=fopen(file,"r"))) {
ERROR("problems opening file %s for reading\n",file);
exit(EXIT_FAILURE);
}
- while(myFgets(string,sizeof(string),fp)) {
+ while(myFgets(string, MAX_STRING_SIZE, fp)) {
count++;
- if(string[0]==CONF_COMMENT) continue;
- numberOfArgs = buffer2array(string,&array);
- if(numberOfArgs==0) continue;
- if(2!=numberOfArgs) {
- ERROR("improperly formated config file at line %i: %s\n",count,string);
+ numberOfArgs = buffer2array(string, &array);
+
+ for(i=0; i<numberOfArgs; i++) {
+ if(array[i][0] == CONF_COMMENT) break;
+ }
+
+ argsMinusComment = i;
+
+ if(0 == argsMinusComment) continue;
+
+ if(2 != argsMinusComment) {
+ ERROR("improperly formated config file at line %i:"
+ " %s\n", count, string);
exit(EXIT_FAILURE);
}
- i = 0;
- while(i<CONF_NUMBER_OF_PARAMS && 0!=strcmp(conf_strings[i],array[0])) i++;
- if(i>=CONF_NUMBER_OF_PARAMS) {
- ERROR("unrecognized paramater in conf at line %i: %s\n",count,string);
+
+ if(!findInList(configEntriesList, array[0], &voidPtr)) {
+ ERROR("unrecognized paramater in config file at line "
+ "%i: %s\n", count, string);
exit(EXIT_FAILURE);
}
-
- if(conf_params[i]!=NULL) {
- if(allowCat[i]) {
- conf_params[i] = realloc(conf_params[i],
- strlen(conf_params[i])+
- strlen(CONF_CAT_CHAR)+
- strlen(array[1])+1);
- strcat(conf_params[i],CONF_CAT_CHAR);
- strcat(conf_params[i],array[1]);
- }
- else {
- free(conf_params[i]);
- conf_params[i] = strdup(array[1]);
+
+ entry = (ConfigEntry *) voidPtr;
+
+ if( !(entry->mask & CONF_REPEATABLE_MASK) &&
+ entry->configParamList->numberOfNodes)
+ {
+ param = entry->configParamList->firstNode->data;
+ ERROR("config paramter \"%s\" is first defined on line "
+ "%i and redefined on line %i\n",
+ array[0], param->line, count);
+ exit(EXIT_FAILURE);
+ }
+
+ if(entry->mask & CONF_BLOCK_MASK) {
+ if(0 != strcmp(array[1], CONF_BLOCK_BEGIN)) {
+ ERROR("improperly formated config file at "
+ "line %i: %s\n", count, string);
+ exit(EXIT_FAILURE);
}
+ param = readConfigBlock(fp, &count, string);
}
- else conf_params[i] = strdup(array[1]);
- free(array[0]);
- free(array[1]);
- free(array);
+ else param = newConfigParam(array[1], count);
+
+ insertInListWithoutKey(entry->configParamList, param);
+
+ freeArgArray(array, numberOfArgs);
}
+}
- fclose(fp);
+ConfigParam * getNextConfigParam(char * name, ConfigParam * last) {
+ void * voidPtr;
+ ConfigEntry * entry;
+ ListNode * node;
+ ConfigParam * param;
- for(i=0;i<CONF_NUMBER_OF_REQUIRED;i++) {
- if(conf_params[conf_required[i]] == NULL) {
- ERROR("%s is unassigned in conf file\n",
- conf_strings[conf_required[i]]);
- exit(EXIT_FAILURE);
+ if(!findInList(configEntriesList, name, &voidPtr)) return NULL;
+
+ entry = voidPtr;
+
+ node = entry->configParamList->firstNode;
+
+ if(last) {
+ while(node!=NULL) {
+ param = node->data;
+ node = node->nextNode;
+ if(param == last) break;
}
}
- for(i=0;i<CONF_NUMBER_OF_PATHS;i++) {
- if(conf_params[conf_absolutePaths[i]] &&
- conf_params[conf_absolutePaths[i]][0]!='/' &&
- conf_params[conf_absolutePaths[i]][0]!='~')
- {
- ERROR("\"%s\" is not an absolute path\n",
- conf_params[conf_absolutePaths[i]]);
- exit(EXIT_FAILURE);
+ if(node == NULL) return NULL;
+
+ param = node->data;
+
+ return param;
+}
+
+char * getConfigParamValue(char * name) {
+ ConfigParam * param = getConfigParam(name);
+
+ if(!param) return NULL;
+
+ return param->value;
+}
+
+char * forceAndGetConfigParamValue(char * name) {
+ ConfigParam * param = getConfigParam(name);
+
+ if(!param) {
+ ERROR("\"%s\" not found in config file\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ return param->value;
+}
+
+BlockParam * getBlockParam(ConfigParam * param, char * name) {
+ BlockParam * ret = NULL;
+ int i;
+
+ for(i = 0; i < param->numberOfBlockParams; i++) {
+ if(0 == strcmp(name, param->blockParams[i].name)) {
+ if(ret) {
+ ERROR("\"%s\" first defined on line %i, and "
+ "redefined on line %i\n", name,
+ ret->line, param->blockParams[i].line);
+ }
+ ret = param->blockParams+i;
}
- /* Parse ~ in path */
- else if(conf_params[conf_absolutePaths[i]] &&
- conf_params[conf_absolutePaths[i]][0]=='~')
- {
- struct passwd * pwd = NULL;
- char * path;
- int pos = 1;
- if(conf_params[conf_absolutePaths[i]][1]=='/' ||
- conf_params[conf_absolutePaths[i]][1]=='\0')
- {
- if(conf_params[CONF_USER] &&
- strlen(conf_params[CONF_USER]))
- {
- pwd = getpwnam(
- conf_params[CONF_USER]);
- if(!pwd) {
- ERROR("no such user: %s\n",
- conf_params[CONF_USER]);
- exit(EXIT_FAILURE);
- }
- }
- else {
- uid_t uid = geteuid();
- if((pwd = getpwuid(uid)) == NULL) {
- ERROR("problems getting passwd "
- "entry "
- "for current user\n");
- exit(EXIT_FAILURE);
- }
+ }
+
+ return ret;
+}
+
+char * parseConfigFilePath(char * name, int force) {
+ ConfigParam * param = getConfigParam(name);
+ char * path;
+
+ if(!param && force) {
+ ERROR("config parameter \"%s\" not found\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ if(!param) return NULL;
+
+ path = param->value;
+
+ if(path[0] != '/' && path[0] != '~') {
+ ERROR("\"%s\" is not an absolute path at line %i\n",
+ param->value, param->line);
+ exit(EXIT_FAILURE);
+ }
+ // Parse ~ in path
+ else if(path[0] == '~') {
+ struct passwd * pwd = NULL;
+ char * newPath;
+ int pos = 1;
+ if(path[1]=='/' || path[1] == '\0') {
+ ConfigParam * userParam = getConfigParam(CONF_USER);
+
+ if(userParam) {
+ pwd = getpwnam(userParam->value);
+ if(!pwd) {
+ ERROR("no such user %s at line %i\n",
+ userParam->value,
+ userParam->line);
+ exit(EXIT_FAILURE);
}
}
else {
- int foundSlash = 0;
- char * ch = &(
- conf_params[conf_absolutePaths[i]][1]);
- for(;*ch!='\0' && *ch!='/';ch++);
- if(*ch=='/') foundSlash = 1;
- * ch = '\0';
- pos+= ch-
- &(conf_params[
- conf_absolutePaths[i]][1]);
- if((pwd = getpwnam(&(conf_params[
- conf_absolutePaths[i]][1]))) == NULL)
- {
- ERROR("user \"%s\" not found\n",
- &(conf_params[
- conf_absolutePaths[i]][1]));
+ uid_t uid = geteuid();
+ if((pwd = getpwuid(uid)) == NULL) {
+ ERROR("problems getting passwd entry "
+ "for current user\n");
exit(EXIT_FAILURE);
}
- if(foundSlash) *ch = '/';
}
- path = malloc(strlen(pwd->pw_dir)+strlen(
- &(conf_params[conf_absolutePaths[i]][pos]))+1);
- strcpy(path,pwd->pw_dir);
- strcat(path,&(conf_params[conf_absolutePaths[i]][pos]));
- free(conf_params[conf_absolutePaths[i]]);
- conf_params[conf_absolutePaths[i]] = path;
}
+ else {
+ int foundSlash = 0;
+ char * ch = path+1;
+ for(;*ch!='\0' && *ch!='/';ch++);
+ if(*ch=='/') foundSlash = 1;
+ * ch = '\0';
+ pos+= ch-path+1;
+ if((pwd = getpwnam(path+1)) == NULL) {
+ ERROR("user \"%s\" not found at line %i\n",
+ path+1, param->line);
+ exit(EXIT_FAILURE);
+ }
+ if(foundSlash) *ch = '/';
+ }
+ newPath = malloc(strlen(pwd->pw_dir)+strlen(path+pos)+1);
+ strcpy(newPath, pwd->pw_dir);
+ strcat(newPath, path+pos);
+ free(param->value);
+ param->value = newPath;
}
- return conf_params;
-}
-
-char ** getConf() {
- return conf_params;
+ return param->value;
}
diff --git a/src/conf.h b/src/conf.h
index f6bd5d283..1c9413654 100644
--- a/src/conf.h
+++ b/src/conf.h
@@ -21,59 +21,72 @@
#include "../config.h"
-#define CONF_PORT 0
-#define CONF_MUSIC_DIRECTORY 1
-#define CONF_PLAYLIST_DIRECTORY 2
-#define CONF_LOG_FILE 3
-#define CONF_ERROR_FILE 4
-#define CONF_CONNECTION_TIMEOUT 5
-#define CONF_MIXER_DEVICE 6
-#define CONF_MAX_CONNECTIONS 7
-#define CONF_MAX_PLAYLIST_LENGTH 8
-#define CONF_BUFFER_BEFORE_PLAY 9
-#define CONF_MAX_COMMAND_LIST_SIZE 10
-#define CONF_MAX_OUTPUT_BUFFER_SIZE 11
-#define CONF_AO_DRIVER 12
-#define CONF_AO_DRIVER_OPTIONS 13
-#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS 14
-#define CONF_BIND_TO_ADDRESS 15
-#define CONF_MIXER_TYPE 16
-#define CONF_STATE_FILE 17
-#define CONF_USER 18
-#define CONF_DB_FILE 19
-#define CONF_LOG_LEVEL 20
-#define CONF_MIXER_CONTROL 21
-#define CONF_AUDIO_WRITE_SIZE 22
-#define CONF_FS_CHARSET 23
-#define CONF_PASSWORD 24
-#define CONF_DEFAULT_PERMISSIONS 25
-#define CONF_BUFFER_SIZE 26
-#define CONF_REPLAYGAIN 27
-#define CONF_AUDIO_OUTPUT_FORMAT 28
-#define CONF_HTTP_PROXY_HOST 29
-#define CONF_HTTP_PROXY_PORT 30
-#define CONF_HTTP_PROXY_USER 31
-#define CONF_HTTP_PROXY_PASSWORD 32
-#define CONF_REPLAYGAIN_PREAMP 33
-#define CONF_SHOUT_HOST 34
-#define CONF_SHOUT_PORT 35
-#define CONF_SHOUT_PASSWD 36
-#define CONF_SHOUT_MOUNT 37
-#define CONF_SHOUT_NAME 38
-#define CONF_SHOUT_USER 39
-#define CONF_SHOUT_QUALITY 40
-#define CONF_ID3V1_ENCODING 41
-#define CONF_SHOUT_FORMAT 42
+#define CONF_PORT "port"
+#define CONF_MUSIC_DIR "music_directory"
+#define CONF_PLAYLIST_DIR "playlist_directory"
+#define CONF_LOG_FILE "log_file"
+#define CONF_ERROR_FILE "error_file"
+#define CONF_CONN_TIMEOUT "connection_timeout"
+#define CONF_MIXER_DEVICE "mixer_device"
+#define CONF_MAX_CONN "max_connections"
+#define CONF_MAX_PLAYLIST_LENGTH "max_playlist_length"
+#define CONF_BUFFER_BEFORE_PLAY "buffer_before_play"
+#define CONF_MAX_COMMAND_LIST_SIZE "max_command_list_size"
+#define CONF_MAX_OUTPUT_BUFFER_SIZE "max_output_buffer_size"
+#define CONF_AUDIO_OUTPUT "audio_output"
+#define CONF_SAVE_ABSOLUTE_PATHS "save_absolute_paths_in_playlists"
+#define CONF_BIND_TO_ADDRESS "bind_to_address"
+#define CONF_MIXER_TYPE "mixer_type"
+#define CONF_STATE_FILE "state_file"
+#define CONF_USER "user"
+#define CONF_DB_FILE "db_file"
+#define CONF_LOG_LEVEL "log_level"
+#define CONF_MIXER_CONTROL "mixer_control"
+#define CONF_AUDIO_WRITE_SIZE "audio_write_size"
+#define CONF_FS_CHARSET "filesystem_charset"
+#define CONF_PASSWORD "password"
+#define CONF_DEFAULT_PERMS "default_permissions"
+#define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size"
+#define CONF_REPLAYGAIN "replaygain"
+#define CONF_AUDIO_OUTPUT_FORMAT "audio_output_format"
+#define CONF_HTTP_PROXY_HOST "http_proxy_host"
+#define CONF_HTTP_PROXY_PORT "http_proxy_port"
+#define CONF_HTTP_PROXY_USER "http_proxy_user"
+#define CONF_HTTP_PROXY_PASSWORD "http_proxy_password"
+#define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
+#define CONF_ID3V1_ENCODING "id3v1_encoding"
-#define CONF_CAT_CHAR "\n"
+typedef struct _BlockParam {
+ char * name;
+ char * value;
+ int line;
+} BlockParam;
-/* do not free the return value, it is a static variable */
-char ** readConf(char * file);
-
-char ** getConf();
+typedef struct _ConfigParam {
+ char * value;
+ unsigned int line;
+ BlockParam * blockParams;
+ int numberOfBlockParams;
+} ConfigParam;
void initConf();
-void writeConf(char * file);
+void readConf(char * file);
+
+/* don't free the returned value
+ set _last_ to NULL to get first entry */
+ConfigParam * getNextConfigParam(char * name, ConfigParam * last);
+
+#define getConfigParam(name) getNextConfigParam(name, NULL)
+
+char * getConfigParamValue(char * name);
+
+char * forceAndGetConfigParamValue(char * name);
+
+void registerConfigParam(char * name, int repeats, int block);
+
+BlockParam * getBlockParam(ConfigParam * param, char * name);
+
+char * parseConfigFilePath(char * name, int force);
#endif
diff --git a/src/directory.c b/src/directory.c
index b5c5ed965..85773489b 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -1053,7 +1053,8 @@ int readDirectoryDB() {
fsCharset = &(buffer[strlen(
DIRECTORY_FS_CHARSET)]);
if((tempCharset =
- getConf()[CONF_FS_CHARSET]) &&
+ getConfigParamValue(
+ CONF_FS_CHARSET)) &&
strcmp(fsCharset,tempCharset))
{
WARNING("Using \"%s\" for the "
diff --git a/src/inputStream_http.c b/src/inputStream_http.c
index 353285ebd..15768929f 100644
--- a/src/inputStream_http.c
+++ b/src/inputStream_http.c
@@ -47,6 +47,11 @@
#define HTTP_REDIRECT_MAX 10
+static char * proxyHost = NULL;
+static int proxyPort = 0;
+static char * proxyUser = NULL;
+static char * proxyPassword = NULL;
+
typedef struct _InputStreemHTTPData {
char * host;
char * path;
@@ -59,57 +64,73 @@ typedef struct _InputStreemHTTPData {
int icyMetaint;
int prebuffer;
int icyOffset;
- char * proxyHost;
- int proxyPort;
char * proxyAuth;
char * httpAuth;
} InputStreamHTTPData;
void inputStream_initHttp() {
- if(getConf()[CONF_HTTP_PROXY_HOST]) {
- char * portStr = getConf()[CONF_HTTP_PROXY_PORT];
- int port = 0;
- char * test;
-
- if(!portStr) {
- ERROR("http_proxy_host specified but not the http_"
- "proxy_port\n");
+ ConfigParam * param = getConfigParam(CONF_HTTP_PROXY_HOST);
+ char * test;
+
+ if(param) {
+ proxyHost = param->value;
+
+ param = getConfigParam(CONF_HTTP_PROXY_PORT);
+
+ if(!param) {
+ ERROR("%s specified but not %s", CONF_HTTP_PROXY_HOST,
+ CONF_HTTP_PROXY_PORT);
exit(EXIT_FAILURE);
}
- port = strtol(portStr, &test, 10);
- if(port <= 0 || *test != '\0') {
- ERROR("http_proxy_port \"%s\" is not a positive integer"
- "\n", portStr);
+ proxyPort = strtol(param->value, &test, 10);
+ if(proxyPort <= 0 || *test != '\0') {
+ ERROR("%s \"%s\" is not a positive integer, line %i\n"
+ CONF_HTTP_PROXY_PORT, param->value,
+ param->line);
}
- if(getConf()[CONF_HTTP_PROXY_USER] &&
- !getConf()[CONF_HTTP_PROXY_PASSWORD])
- {
- ERROR("http_proxy_user specified, but not http_proxy_"
- "password\n");
- exit(EXIT_FAILURE);
+ param = getConfigParam(CONF_HTTP_PROXY_USER);
+
+ if(param) {
+ proxyUser = param->value;
+
+ param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
+
+ if(!param) {
+ ERROR("%s specifid but not %s\n",
+ CONF_HTTP_PROXY_USER,
+ CONF_HTTP_PROXY_PASSWORD);
+ exit(EXIT_FAILURE);
+ }
+
+ proxyPassword = param->value;
}
- if(getConf()[CONF_HTTP_PROXY_PASSWORD] &&
- !getConf()[CONF_HTTP_PROXY_USER])
- {
- ERROR("http proxy password specified, but not http "
- "proxy user\n");
+ param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
+
+ if(param) {
+ ERROR("%s specifid but not %s\n",
+ CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_USER);
exit(EXIT_FAILURE);
}
}
- else if(getConf()[CONF_HTTP_PROXY_PORT]) {
- ERROR("http_proxy_port specified but not http_proxy_host\n");
+ else if((param = getConfigParam(CONF_HTTP_PROXY_PORT))) {
+ ERROR("%s specified but not %s, line %i\n",
+ CONF_HTTP_PROXY_PORT, CONF_HTTP_PROXY_HOST,
+ param->line);
exit(EXIT_FAILURE);
}
- else if(getConf()[CONF_HTTP_PROXY_USER]) {
- ERROR("http_proxy_user specified but not http_proxy_host\n");
+ else if((param = getConfigParam(CONF_HTTP_PROXY_USER))) {
+ ERROR("%s specified but not %s, line %i\n",
+ CONF_HTTP_PROXY_USER, CONF_HTTP_PROXY_HOST,
+ param->line);
exit(EXIT_FAILURE);
}
- else if(getConf()[CONF_HTTP_PROXY_PASSWORD]) {
- ERROR("http_proxy_password specified but not http_proxy_host"
- "\n");
+ else if((param = getConfigParam(CONF_HTTP_PROXY_PASSWORD))) {
+ ERROR("%s specified but not %s, line %i\n",
+ CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_HOST,
+ param->line);
exit(EXIT_FAILURE);
}
}
@@ -188,19 +209,10 @@ static char * authString(char * header, char * user, char * password) {
static InputStreamHTTPData * newInputStreamHTTPData() {
InputStreamHTTPData * ret = malloc(sizeof(InputStreamHTTPData));
- if(getConf()[CONF_HTTP_PROXY_HOST]) {
- ret->proxyHost = getConf()[CONF_HTTP_PROXY_HOST];
- DEBUG(__FILE__ ": Proxy host %s\n", ret->proxyHost);
- ret->proxyPort = atoi(getConf()[CONF_HTTP_PROXY_PORT]);
- DEBUG(__FILE__ ": Proxy port %i\n", ret->proxyPort);
- ret->proxyAuth = proxyAuthString(
- getConf()[CONF_HTTP_PROXY_USER],
- getConf()[CONF_HTTP_PROXY_PASSWORD]);
- }
- else {
- ret->proxyHost = NULL;
- ret->proxyAuth = NULL;
+ if(proxyHost) {
+ ret->proxyAuth = proxyAuthString(proxyUser, proxyPassword);
}
+ else ret->proxyAuth = NULL;
ret->httpAuth = NULL;
ret->host = NULL;
@@ -299,7 +311,7 @@ static int parseUrl(InputStreamHTTPData * data, char * url) {
}
/* fetch the path */
- if(data->proxyHost) data->path = strdup(url);
+ if(proxyHost) data->path = strdup(url);
else data->path = strdup(slash ? slash : "/");
return 0;
@@ -319,9 +331,9 @@ static int initHTTPConnection(InputStream * inStream) {
struct sockaddr_in6 sin6;
#endif
- if(data->proxyHost) {
- connHost = data->proxyHost;
- connPort = data->proxyPort;
+ if(proxyHost) {
+ connHost = proxyHost;
+ connPort = proxyPort;
}
else {
connHost = data->host;
diff --git a/src/interface.c b/src/interface.c
index 196ff7706..4282b89be 100644
--- a/src/interface.c
+++ b/src/interface.c
@@ -47,12 +47,18 @@
#define INTERFACE_LIST_MODE_BEGIN "command_list_begin"
#define INTERFACE_LIST_OK_MODE_BEGIN "command_list_ok_begin"
#define INTERFACE_LIST_MODE_END "command_list_end"
-#define INTERFACE_DEFAULT_OUT_BUFFER_SIZE 4096
-
-int interface_max_connections = 0;
-int interface_timeout;
-unsigned long long interface_max_command_list_size;
-unsigned long long interface_max_output_buffer_size;
+#define INTERFACE_DEFAULT_OUT_BUFFER_SIZE 4096
+#define INTERFACE_TIMEOUT_DEFAULT 60
+#define INTERFACE_MAX_CONNECTIONS_DEFAULT 10
+#define INTERFACE_MAX_COMMAND_LIST_DEFAULT (2048*1024)
+#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (2048*1024)
+
+static int interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT;
+static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT;
+static size_t interface_max_command_list_size =
+ INTERFACE_MAX_COMMAND_LIST_DEFAULT;
+static size_t interface_max_output_buffer_size =
+ INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT;
typedef struct _Interface {
char buffer[INTERFACE_MAX_BUFFER_LENGTH+2];
@@ -420,33 +426,58 @@ int doIOForInterfaces() {
void initInterfaces() {
int i;
char * test;
+ ConfigParam * param;
- interface_timeout = strtol((getConf())[CONF_CONNECTION_TIMEOUT],&test,10);
- if(*test!='\0' || interface_timeout<=0) {
- ERROR("connection timeout \"%s\" is not a positive integer\n",(getConf())[CONF_CONNECTION_TIMEOUT]);
- exit(EXIT_FAILURE);
- }
+ param = getConfigParam(CONF_CONN_TIMEOUT);
- interface_max_connections = strtol((getConf())[CONF_MAX_CONNECTIONS],&test,10);
- if(*test!='\0' || interface_max_connections<=0) {
- ERROR("max connections \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_CONNECTIONS]);
- exit(EXIT_FAILURE);
+ if(param) {
+ interface_timeout = strtol(param->value,&test,10);
+ if(*test!='\0' || interface_timeout<=0) {
+ ERROR("connection timeout \"%s\" is not a positive "
+ "integer, line %i\n", CONF_CONN_TIMEOUT,
+ param->line);
+ exit(EXIT_FAILURE);
+ }
}
- interface_max_command_list_size = strtoll((getConf())[CONF_MAX_COMMAND_LIST_SIZE],&test,10);
- if(*test!='\0' || interface_max_command_list_size<=0) {
- ERROR("max command list size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_COMMAND_LIST_SIZE]);
- exit(EXIT_FAILURE);
+ param = getConfigParam(CONF_MAX_CONN);
+
+ if(param) {
+ interface_max_connections = strtol(param->value, &test, 10);
+ if(*test!='\0' || interface_max_connections<=0) {
+ ERROR("max connections \"%s\" is not a positive integer"
+ ", line %i\n", param->value, param->line);
+ exit(EXIT_FAILURE);
+ }
}
- interface_max_output_buffer_size = strtoll((getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE],&test,10);
- if(*test!='\0' || interface_max_output_buffer_size<=0) {
- ERROR("max output buffer size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE]);
- exit(EXIT_FAILURE);
+ param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE);
+
+ if(param) {
+ interface_max_command_list_size = strtoll(param->value,
+ &test, 10);
+ if(*test!='\0' || interface_max_command_list_size<=0) {
+ ERROR("max command list size \"%s\" is not a positive "
+ "integer, line %i\n", param->value,
+ param->line);
+ exit(EXIT_FAILURE);
+ }
+ interface_max_command_list_size*=1024;
}
- interface_max_command_list_size*=1024;
- interface_max_output_buffer_size*=1024;
+ param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE);
+
+ if(param) {
+ interface_max_output_buffer_size = strtoll(param->value, &test,
+ 10);
+ if(*test!='\0' || interface_max_output_buffer_size<=0) {
+ ERROR("max output buffer size \"%s\" is not a positive "
+ "integer, line %i\n", param->value,
+ param->line);
+ exit(EXIT_FAILURE);
+ }
+ interface_max_output_buffer_size*=1024;
+ }
interfaces = malloc(sizeof(Interface)*interface_max_connections);
diff --git a/src/list.c b/src/list.c
index 68ec8d9c3..8faa271c0 100644
--- a/src/list.c
+++ b/src/list.c
@@ -192,7 +192,7 @@ int findInList(List * list,char * key,void ** data) {
tmpNode = list->nodesArray[cur];
cmp = strcmp(tmpNode->key,key);
if(cmp==0) {
- (*data) = tmpNode->data;
+ if(data) *data = tmpNode->data;
return 1;
}
else if(cmp>0) high = cur;
diff --git a/src/list.h b/src/list.h
index 7b08e7e51..9c879e91a 100644
--- a/src/list.h
+++ b/src/list.h
@@ -88,6 +88,7 @@ void deleteNodeFromList(List * list,ListNode * node);
* _key_ -> which node is being searched for
* _data_ -> a pointer to where data will be placed,
* _data_ memory should not by allocated or freed
+ * _data_ can be NULL
* returns 1 if successful, 0 otherwise
*/
int findInList(List * list, char * key, void ** data);
diff --git a/src/listen.c b/src/listen.c
index 49ff4c33e..065e1ccc6 100644
--- a/src/listen.c
+++ b/src/listen.c
@@ -44,6 +44,7 @@
int listenSocket;
int establish(unsigned short port) {
+ ConfigParam * param;
int allowReuse = ALLOW_REUSE;
int sock;
struct sockaddr * addrp;
@@ -60,8 +61,10 @@ int establish(unsigned short port) {
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
+
+ param = getConfigParam(CONF_BIND_TO_ADDRESS);
- if(strcmp((getConf())[CONF_BIND_TO_ADDRESS],"any")==0) {
+ if(!param || 0==strcmp(param->value, "any")==0) {
#ifdef HAVE_IPV6
if(ipv6Supported()) {
sin6.sin6_addr = in6addr_any;
@@ -78,9 +81,9 @@ int establish(unsigned short port) {
}
else {
struct hostent * he;
- if(!(he = gethostbyname((getConf())[CONF_BIND_TO_ADDRESS]))) {
- ERROR("can't lookup host \"%s\"\n",
- (getConf())[CONF_BIND_TO_ADDRESS]);
+ if(!(he = gethostbyname(param->value))) {
+ ERROR("can't lookup host \"%s\" at line %i\n",
+ param->value, param->line);
exit(EXIT_FAILURE);
}
switch(he->h_addrtype) {
@@ -88,8 +91,8 @@ int establish(unsigned short port) {
case AF_INET6:
if(!ipv6Supported()) {
ERROR("no IPv6 support, but a IPv6 address "
- "found for \"%s\"\n",
- (getConf())[CONF_BIND_TO_ADDRESS]);
+ "found for \"%s\" at line %i\n",
+ param->value, param->line);
exit(EXIT_FAILURE);
}
bcopy((char *)he->h_addr,(char *)
@@ -105,8 +108,9 @@ int establish(unsigned short port) {
addrlen = sizeof(struct sockaddr_in);
break;
default:
- ERROR("address type for \"%s\" is not IPv4 or IPv6\n",
- (getConf())[CONF_BIND_TO_ADDRESS]);
+ ERROR("address type for \"%s\" is not IPv4 or IPv6 "
+ "at line %i\n",
+ param->value, param->line);
exit(EXIT_FAILURE);
}
}
diff --git a/src/log.c b/src/log.c
index 835fa9e00..964b8aa66 100644
--- a/src/log.c
+++ b/src/log.c
@@ -32,16 +32,24 @@ short warningFlushed = 0;
static char * warningBuffer = NULL;
void initLog() {
- if(strcmp(getConf()[CONF_LOG_LEVEL],"default")==0) {
+ ConfigParam * param = getConfigParam(CONF_LOG_LEVEL);
+
+ if(!param) return;
+
+ if(0 == strcmp(param->value, "default")) {
if(logLevel<LOG_LEVEL_LOW) logLevel = LOG_LEVEL_LOW;
}
- else if(strcmp(getConf()[CONF_LOG_LEVEL],"secure")==0) {
+ else if(0 == strcmp(param->value, "secure")) {
if(logLevel<LOG_LEVEL_SECURE) logLevel = LOG_LEVEL_SECURE;
}
- else if(strcmp(getConf()[CONF_LOG_LEVEL],"verbose")==0) {
+ else if(0 == strcmp(param->value, "verbose")) {
if(logLevel<LOG_LEVEL_DEBUG) logLevel = LOG_LEVEL_DEBUG;
}
- else ERROR("unknown log level \"%s\"\n",getConf()[CONF_LOG_LEVEL]);
+ else {
+ ERROR("unknown log level \"%s\" at line %i\n",
+ param->value, param->line);
+ exit(EXIT_FAILURE);
+ }
}
#define BUFFER_LENGTH 4096
diff --git a/src/main.c b/src/main.c
index ddde281a7..f56d74939 100644
--- a/src/main.c
+++ b/src/main.c
@@ -165,9 +165,12 @@ void parseOptions(int argc, char ** argv, Options * options) {
return;
}
else if(argcLeft<=2) {
- char ** conf = NULL;
- if(argcLeft==2) conf = readConf(argv[argc-1]);
- if(argcLeft==1) {
+ int conf = 0;
+ if(argcLeft==2) {
+ readConf(argv[argc-1]);
+ conf = 1;
+ }
+ else if(argcLeft==1) {
FILE * fp;
char * homedir = getenv("HOME");
char userfile[MAXPATHLEN+1] = "";
@@ -179,23 +182,27 @@ void parseOptions(int argc, char ** argv, Options * options) {
}
if(strlen(userfile) && (fp=fopen(userfile,"r"))) {
fclose(fp);
- conf = readConf(userfile);
+ readConf(userfile);
+ conf = 1;
}
else if((fp=fopen(SYSTEM_CONFIG_FILE_LOCATION,"r"))) {
fclose(fp);
- conf = readConf(SYSTEM_CONFIG_FILE_LOCATION);
+ readConf(SYSTEM_CONFIG_FILE_LOCATION);
+ conf = 1;
}
}
if(conf) {
- options->portStr = conf[CONF_PORT];
- options->musicDirArg = conf[CONF_MUSIC_DIRECTORY];
- options->playlistDirArg = conf[CONF_PLAYLIST_DIRECTORY];
- options->logFile = conf[CONF_LOG_FILE];
- options->errorFile = conf[CONF_ERROR_FILE];
- options->usr = conf[CONF_USER];
- if(conf[CONF_DB_FILE]) {
- options->dbFile = conf[CONF_DB_FILE];
- }
+ options->portStr = forceAndGetConfigParamValue(
+ CONF_PORT);
+ options->musicDirArg =
+ parseConfigFilePath(CONF_MUSIC_DIR, 1);
+ options->playlistDirArg =
+ parseConfigFilePath(CONF_PLAYLIST_DIR, 1);
+ options->logFile = parseConfigFilePath(CONF_LOG_FILE,1);
+ options->errorFile =
+ parseConfigFilePath(CONF_ERROR_FILE, 1);
+ options->usr = parseConfigFilePath(CONF_USER, 0);
+ options->dbFile = parseConfigFilePath(CONF_DB_FILE, 0);
return;
}
}
diff --git a/src/path.c b/src/path.c
index 48d5eff09..1d599bda3 100644
--- a/src/path.c
+++ b/src/path.c
@@ -114,6 +114,7 @@ void initPaths(char * playlistDirArg, char * musicDirArg) {
char * charset = NULL;
char * originalLocale;
struct stat st;
+ ConfigParam * param;
playlistDir = prependCwdToPathDup(playlistDirArg);
if((stat(playlistDir,&st))<0) {
@@ -135,8 +136,10 @@ void initPaths(char * playlistDirArg, char * musicDirArg) {
exit(EXIT_FAILURE);
}
- if(getConf()[CONF_FS_CHARSET]) {
- charset = strdup(getConf()[CONF_FS_CHARSET]);
+ param = getConfigParam(CONF_FS_CHARSET);
+
+ if(param) {
+ charset = strdup(param->value);
}
#ifdef HAVE_LOCALE
#ifdef HAVE_LANGINFO_CODESET
@@ -296,5 +299,3 @@ char * prependCwdToPathDup(char * path) {
return realloc(ret,len+1);
}
-
-/* vim:set shiftwidth=4 tabstop=8 expandtab: */
diff --git a/src/permission.c b/src/permission.c
index e9e74ad7a..795fe577d 100644
--- a/src/permission.c
+++ b/src/permission.c
@@ -69,56 +69,53 @@ unsigned int parsePermissions(char * string) {
}
void initPermissions() {
- char * passwordSets;
- char * nextSet;
char * temp;
- char * cp1;
char * cp2;
char * password;
unsigned int * permission;
+ ConfigParam * param;
permission_passwords = makeList(free);
permission_default = PERMISSION_READ | PERMISSION_ADD |
PERMISSION_CONTROL | PERMISSION_ADMIN;
- if(getConf()[CONF_DEFAULT_PERMISSIONS]) {
- permission_default = parsePermissions(
- getConf()[CONF_DEFAULT_PERMISSIONS]);
- }
-
- if(!getConf()[CONF_PASSWORD]) return;
-
- if(!getConf()[CONF_DEFAULT_PERMISSIONS]) permission_default = 0;
+ param = getNextConfigParam(CONF_PASSWORD, NULL);
- passwordSets = strdup(getConf()[CONF_PASSWORD]);
+ if(param) {
+ permission_default = 0;
- nextSet = strtok_r(passwordSets,CONF_CAT_CHAR,&cp1);
- while(nextSet && strlen(nextSet)) {
- if(!strstr(nextSet,PERMISSION_PASSWORD_CHAR)) {
- ERROR("\"%s\" not found in password string \"%s\"\n",
+ do {
+ if(!strstr(param->value, PERMISSION_PASSWORD_CHAR)) {
+ ERROR("\"%s\" not found in password string "
+ "\"%s\", line %i\n",
PERMISSION_PASSWORD_CHAR,
- nextSet);
- exit(EXIT_FAILURE);
- }
+ param->value,
+ param->line);
+ exit(EXIT_FAILURE);
+ }
- if(!(temp = strtok_r(nextSet,PERMISSION_PASSWORD_CHAR,&cp2))) {
- ERROR("something weird just happend in permission.c\n");
- exit(EXIT_FAILURE);
- }
- password = temp;
+ if(!(temp = strtok_r(param->value,
+ PERMISSION_PASSWORD_CHAR,&cp2))) {
+ ERROR("something weird just happend in permission.c\n");
+ exit(EXIT_FAILURE);
+ }
- permission = malloc(sizeof(unsigned int));
- *permission = parsePermissions(strtok_r(NULL,"",&cp2));
+
+ password = temp;
- insertInList(permission_passwords,password,permission);
+ permission = malloc(sizeof(unsigned int));
+ *permission = parsePermissions(strtok_r(NULL,"",&cp2));
- nextSet = strtok_r(NULL,CONF_CAT_CHAR,&cp1);
+ insertInList(permission_passwords,password,permission);
+ } while((param = getNextConfigParam(CONF_PASSWORD, param)));
}
- sortList(permission_passwords);
+ param = getConfigParam(CONF_DEFAULT_PERMS);
- free(passwordSets);
+ if(param) permission_default = parsePermissions(param->value);
+
+ sortList(permission_passwords);
}
int getPermissionFromPassword(char * password, unsigned int * permission) {
diff --git a/src/playerData.c b/src/playerData.c
index 5804f306c..b851a99f9 100644
--- a/src/playerData.c
+++ b/src/playerData.c
@@ -30,23 +30,32 @@
int buffered_before_play;
int buffered_chunks;
+#define DEFAULT_BUFFER_SIZE 2048
+#define DEFAULT_BUFFER_BEFORE_PLAY 25
+
PlayerData * playerData_pd;
void initPlayerData() {
- float perc;
+ float perc = DEFAULT_BUFFER_BEFORE_PLAY;
char * test;
int shmid;
int crossfade = 0;
- size_t bufferSize;
+ size_t bufferSize = DEFAULT_BUFFER_SIZE;
size_t allocationSize;
OutputBuffer * buffer;
+ ConfigParam * param;
- bufferSize = strtol(getConf()[CONF_BUFFER_SIZE],&test,10);
- if(*test!='\0' || bufferSize<=0) {
- ERROR("buffer size \"%s\" is not a positive integer\n",
- getConf()[CONF_BUFFER_SIZE]);
- exit(EXIT_FAILURE);
+ param = getConfigParam(CONF_AUDIO_BUFFER_SIZE);
+
+ if(param) {
+ bufferSize = strtol(param->value, &test, 10);
+ if(*test!='\0' || bufferSize<=0) {
+ ERROR("buffer size \"%s\" is not a positive integer, "
+ "line %i\n", param->value, param->line);
+ exit(EXIT_FAILURE);
+ }
}
+
bufferSize*=1024;
buffered_chunks = bufferSize/CHUNK_SIZE;
@@ -56,13 +65,18 @@ void initPlayerData() {
exit(EXIT_FAILURE);
}
- perc = strtod((getConf())[CONF_BUFFER_BEFORE_PLAY],&test);
- if(*test!='%' || perc<0 || perc>100) {
- ERROR("buffered before play \"%s\" is not a positive "
- "percentage and less than 100 percent\n",
- (getConf())[CONF_BUFFER_BEFORE_PLAY]);
- exit(EXIT_FAILURE);
+ param = getConfigParam(CONF_BUFFER_BEFORE_PLAY);
+
+ if(param) {
+ perc = strtod(param->value, &test);
+ if(*test!='%' || perc<0 || perc>100) {
+ ERROR("buffered before play \"%s\" is not a positive "
+ "percentage and less than 100 percent, line %i"
+ "\n", param->value, param->line);
+ exit(EXIT_FAILURE);
+ }
}
+
buffered_before_play = (perc/100)*buffered_chunks;
if(buffered_before_play>buffered_chunks) {
buffered_before_play = buffered_chunks;
diff --git a/src/playlist.c b/src/playlist.c
index fd1873f93..74bb56116 100644
--- a/src/playlist.c
+++ b/src/playlist.c
@@ -60,6 +60,9 @@
#define PLAYLIST_HASH_MULT 4
+#define DEFAULT_PLAYLIST_MAX_LENGTH (1024*16)
+#define DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS 0
+
typedef struct _Playlist {
Song ** songs;
/* holds version a song was modified on */
@@ -77,13 +80,13 @@ typedef struct _Playlist {
static Playlist playlist;
static int playlist_state = PLAYLIST_STATE_STOP;
-static int playlist_max_length;
+static int playlist_max_length = DEFAULT_PLAYLIST_MAX_LENGTH;
static int playlist_stopOnError;
static int playlist_errorCount = 0;
static int playlist_queueError;
static int playlist_noGoToNext = 0;
-static int playlist_saveAbsolutePaths;
+static int playlist_saveAbsolutePaths = DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS;
static char * playlist_stateFile = NULL;
@@ -128,6 +131,7 @@ static void incrPlaylistCurrent() {
void initPlaylist() {
char * test;
int i;
+ ConfigParam * param;
playlist.length = 0;
playlist.repeat = 0;
@@ -136,26 +140,32 @@ void initPlaylist() {
playlist.queued = -1;
playlist.current = -1;
- playlist_max_length = strtol((getConf())[CONF_MAX_PLAYLIST_LENGTH],&test,10);
- if(*test!='\0') {
- ERROR("max playlist length \"%s\" is not an integer\n",
- (getConf())[CONF_MAX_PLAYLIST_LENGTH]);
- exit(EXIT_FAILURE);
- }
+ param = getConfigParam(CONF_MAX_PLAYLIST_LENGTH);
- if(strcmp("yes",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS])
- ==0) {
- playlist_saveAbsolutePaths = 1;
- }
- else if(strcmp("no",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS])
- ==0) {
- playlist_saveAbsolutePaths = 0;
+ if(param) {
+ playlist_max_length = strtol(param->value, &test, 10);
+ if(*test!='\0') {
+ ERROR("max playlist length \"%s\" is not an integer, "
+ "line %i\n", param->value, param->line);
+ exit(EXIT_FAILURE);
+ }
}
- else {
- ERROR("save_absolute_paths_in_playlist \"%s\" is not yes or "
- "no\n",
- (getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS]);
- exit(EXIT_FAILURE);
+
+ param = getConfigParam(CONF_SAVE_ABSOLUTE_PATHS);
+
+ if(param) {
+ if(0 == strcmp("yes", param->value) ) {
+ playlist_saveAbsolutePaths = 1;
+ }
+ else if(0 == strcmp("no", param->value) ) {
+ playlist_saveAbsolutePaths = 0;
+ }
+ else {
+ ERROR("%s \"%s\" is not yes or no, line %i"
+ CONF_SAVE_ABSOLUTE_PATHS,
+ param->value, param->line);
+ exit(EXIT_FAILURE);
+ }
}
playlist.songs = malloc(sizeof(Song *)*playlist_max_length);
@@ -169,9 +179,7 @@ void initPlaylist() {
srand(time(NULL));
- if(getConf()[CONF_STATE_FILE]) {
- playlist_stateFile = getConf()[CONF_STATE_FILE];
- }
+ playlist_stateFile = getConfigParamValue(CONF_STATE_FILE);
for(i=0; i<playlist_max_length*PLAYLIST_HASH_MULT; i++) {
playlist.idToPosition[i] = -1;
diff --git a/src/replayGain.c b/src/replayGain.c
index dbd09aa36..4788d7d95 100644
--- a/src/replayGain.c
+++ b/src/replayGain.c
@@ -32,34 +32,38 @@ static int replayGainState = REPLAYGAIN_OFF;
static float replayGainPreamp = 1.0;
void initReplayGainState() {
- if(!getConf()[CONF_REPLAYGAIN]) return;
+ ConfigParam * param = getConfigParam(CONF_REPLAYGAIN);
- if(strcmp(getConf()[CONF_REPLAYGAIN],"track")==0) {
+ if(!param) return;
+
+ if(strcmp(param->value, "track") == 0) {
replayGainState = REPLAYGAIN_TRACK;
}
- else if(strcmp(getConf()[CONF_REPLAYGAIN],"album")==0) {
+ else if(strcmp(param->value, "album") == 0) {
replayGainState = REPLAYGAIN_ALBUM;
}
else {
- ERROR("replaygain value \"%s\" is invalid\n",
- getConf()[CONF_REPLAYGAIN]);
+ ERROR("replaygain value \"%s\" at line %i is invalid\n",
+ param->value, param->line);
exit(EXIT_FAILURE);
}
- if(getConf()[CONF_REPLAYGAIN_PREAMP]) {
+ param = getConfigParam(CONF_REPLAYGAIN_PREAMP);
+
+ if(param) {
char * test;
- float f = strtod(getConf()[CONF_REPLAYGAIN_PREAMP], &test);
+ float f = strtod(param->value, &test);
if(*test != '\0') {
- ERROR("Replaygain preamp \"%s\" is not a number\n",
- getConf()[CONF_REPLAYGAIN_PREAMP]);
+ ERROR("Replaygain preamp \"%s\" is not a number at "
+ "line %i\n", param->value, param->line);
exit(EXIT_FAILURE);
}
if(f < -15 || f > 15) {
ERROR("Replaygain preamp \"%s\" is not between -15 and"
- "15\n",
- getConf()[CONF_REPLAYGAIN_PREAMP]);
+ "15 at line %i\n",
+ param->value, param->line);
exit(EXIT_FAILURE);
}
diff --git a/src/tag.c b/src/tag.c
index 08b620289..b5c71c500 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -93,18 +93,6 @@ char * getID3Info(struct id3_tag * tag, char * id) {
utf8 = id3_ucs4_utf8duplicate(ucs4);
if(!utf8) return NULL;
- if(getConf()[CONF_ID3V1_ENCODING]
- && (id3_tag_options(tag, 0, 0) & ID3_TAG_OPTION_ID3V1)) {
-
- char* isostr;
- setCharSetConversion("ISO-8859-1", "UTF-8");
- isostr = convStrDup(utf8);
- free(utf8);
- setCharSetConversion("UTF-8", getConf()[CONF_ID3V1_ENCODING]);
- utf8 = convStrDup(isostr);
- free(isostr);
- }
-
return utf8;
}
#endif
diff --git a/src/volume.c b/src/volume.c
index fa2f8aaa9..cd48f76f4 100644
--- a/src/volume.c
+++ b/src/volume.c
@@ -45,8 +45,21 @@
#define VOLUME_MIXER_ALSA_DEFAULT "default"
#define VOLUME_MIXER_ALSA_CONTROL_DEFAULT "Master"
-int volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
-char * volume_mixerDevice;
+#ifndef NO_OSS_MIXER
+#define VOLUME_MIXER_TYPE_DEFAULT VOLUME_MIXER_TYPE_OSS
+#define VOLUME_MIXER_DEVICE_DEFAULT VOLUME_MIXER_OSS_DEFAULT
+#else
+#ifdef HAVE_ALSA
+#define VOLUME_MIXER_TYPE_DEFAULT VOLUME_MIXER_TYPE_ALSA
+#define VOLUME_MIXER_DEVICE_DEFAULT VOLUME_MIXER_ALSA_DEFAULT
+#else
+#define VOLUME_MIXER_TYPE_DEFAULT VOLUME_MIXER_TYPE_SOFTWARE
+#define VOLUME_MIXER_DEVICE_DEFAULT VOLUME_MIXER_SOFTWARE_DEFAULT
+#endif
+#endif
+
+int volume_mixerType = VOLUME_MIXER_TYPE_DEFAULT;
+char * volume_mixerDevice = VOLUME_MIXER_DEVICE_DEFAULT;
int volume_softwareSet = 100;
@@ -66,13 +79,16 @@ int volume_alsaSet = -1;
#ifndef NO_OSS_MIXER
int prepOssMixer(char * device) {
int devmask = 0;
+ ConfigParam * param;
if((volume_ossFd = open(device,O_RDONLY))<0) {
WARNING("unable to open oss mixer \"%s\"\n",device);
return -1;
}
- if(getConf()[CONF_MIXER_CONTROL]) {
+ param = getConfigParam(CONF_MIXER_CONTROL);
+
+ if(param) {
char * labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
char * dup;
int i,j;
@@ -88,7 +104,7 @@ int prepOssMixer(char * device) {
/* eliminate spaces at the end */
j = strlen(dup)-1;
while(j>=0 && dup[j]==' ') dup[j--] = '\0';
- if(strcasecmp(dup,getConf()[CONF_MIXER_CONTROL])==0) {
+ if(strcasecmp(dup, param->value)==0) {
free(dup);
break;
}
@@ -96,14 +112,14 @@ int prepOssMixer(char * device) {
}
if(i>=SOUND_MIXER_NRDEVICES) {
- WARNING("mixer control \"%s\" not found\n",
- getConf()[CONF_MIXER_CONTROL]);
+ WARNING("mixer control \"%s\" not found at line %i\n",
+ param->value, param->line);
close(volume_ossFd);
return -1;
}
else if(!( ( 1 << i ) & devmask )) {
- WARNING("mixer control \"%s\" not usable\n",
- getConf()[CONF_MIXER_CONTROL]);
+ WARNING("mixer control \"%s\" not usable at line %i\n",
+ param->value, param->line);
close(volume_ossFd);
return -1;
}
@@ -173,6 +189,7 @@ int prepAlsaMixer(char * card) {
int err;
snd_mixer_elem_t * elem;
char * controlName = VOLUME_MIXER_ALSA_CONTROL_DEFAULT;
+ ConfigParam * param;
if((err = snd_mixer_open(&volume_alsaMixerHandle,0))<0) {
WARNING("problems opening alsa mixer: %s\n",snd_strerror(err));
@@ -201,8 +218,11 @@ int prepAlsaMixer(char * card) {
}
elem = snd_mixer_first_elem(volume_alsaMixerHandle);
- if(getConf()[CONF_MIXER_CONTROL]) {
- controlName = getConf()[CONF_MIXER_CONTROL];
+
+ param = getConfigParam(CONF_MIXER_CONTROL);
+
+ if(param) {
+ controlName = param->value;
}
while(elem) {
@@ -340,29 +360,37 @@ void finishVolume() {
}
void initVolume() {
- if(0);
+ ConfigParam * param = getConfigParam(CONF_MIXER_TYPE);
+
+ if(param) {
+ if(0);
#ifdef HAVE_ALSA
- else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_ALSA)==0) {
- volume_mixerType = VOLUME_MIXER_TYPE_ALSA;
- volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT;
- }
+ else if(strcmp(param->value, VOLUME_MIXER_ALSA)==0) {
+ volume_mixerType = VOLUME_MIXER_TYPE_ALSA;
+ volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT;
+ }
#endif
#ifndef NO_OSS_MIXER
- else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_OSS)==0) {
- volume_mixerType = VOLUME_MIXER_TYPE_OSS;
- volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT;
- }
+ else if(strcmp(param->value, VOLUME_MIXER_OSS)==0) {
+ volume_mixerType = VOLUME_MIXER_TYPE_OSS;
+ volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT;
+ }
#endif
- else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_SOFTWARE)==0) {
- volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
- volume_mixerDevice = VOLUME_MIXER_SOFTWARE_DEFAULT;
- }
- else {
- ERROR("unknown mixer type: %s\n",(getConf())[CONF_MIXER_TYPE]);
- exit(EXIT_FAILURE);
+ else if(strcmp(param->value ,VOLUME_MIXER_SOFTWARE)==0) {
+ volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
+ volume_mixerDevice = VOLUME_MIXER_SOFTWARE_DEFAULT;
+ }
+ else {
+ ERROR("unknown mixer type %s at line %i\n",
+ param->value, param->line);
+ exit(EXIT_FAILURE);
+ }
}
- if(strlen((getConf())[CONF_MIXER_DEVICE])) {
- volume_mixerDevice = (getConf())[CONF_MIXER_DEVICE];
+
+ param = getConfigParam(CONF_MIXER_DEVICE);
+
+ if(param) {
+ volume_mixerDevice = param->value;
}
}
@@ -431,4 +459,3 @@ int changeVolumeLevel(FILE * fp, int change, int rel) {
break;
}
}
-/* vim:set shiftwidth=4 tabstop=8 expandtab: */