summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars-Dominik Braun <lars@6xq.net>2015-09-25 17:44:58 +0200
committerLars-Dominik Braun <lars@6xq.net>2015-09-25 17:52:33 +0200
commit9dbd0f308b10f6a2982e72f25b0d26c951f5e87f (patch)
tree419e6f5d29449478ea869298c94fae66f6f458e1
parent77ffe368e9b5045a801360c563623d5bc1c78771 (diff)
downloadpianobar-9dbd0f308b10f6a2982e72f25b0d26c951f5e87f.tar.gz
pianobar-9dbd0f308b10f6a2982e72f25b0d26c951f5e87f.tar.bz2
pianobar-9dbd0f308b10f6a2982e72f25b0d26c951f5e87f.zip
settings: Fix config file parser
scanf’s %s matches non-whitespace characters only and thus ‘# foo = bar’ is parsed as ‘foo’, ‘bar’ and not ‘# foo’, ‘bar’ (as expected). Thus comments did not work if they a) started with a valid key and b) had a space between hash-sign and key. Fixes issue #526.
-rw-r--r--contrib/pianobar.14
-rw-r--r--src/settings.c67
2 files changed, 61 insertions, 10 deletions
diff --git a/contrib/pianobar.1 b/contrib/pianobar.1
index ee09c41..375ec47 100644
--- a/contrib/pianobar.1
+++ b/contrib/pianobar.1
@@ -37,9 +37,7 @@ http://xiph.org/ao/doc/config.html
.SH CONFIGURATION
The configuration file consists of simple
.B key = value
-lines, each terminated with a newline (\\n) character. Note that keys and
-values are both case sensitive, and there must be exactly one space on each
-side of the equals sign.
+lines, each terminated with a newline (\\n) character. Keys are case sensitive.
act_* keys control
.B pianobar's
diff --git a/src/settings.c b/src/settings.c
index 11a2982..f98874c 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2012
+Copyright (c) 2008-2015
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,11 +33,13 @@ THE SOFTWARE.
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
+#include <ctype.h>
#include <piano.h>
#include "settings.h"
#include "config.h"
+#include "ui.h"
#include "ui_dispatch.h"
#define streq(a, b) (strcmp (a, b) == 0)
@@ -197,8 +199,10 @@ void BarSettingsRead (BarSettings_t *settings) {
/* read config files */
for (size_t j = 0; j < sizeof (configfiles) / sizeof (*configfiles); j++) {
static const char *formatMsgPrefix = "format_msg_";
- char key[256], val[256];
FILE *configfd;
+ /* getline allocates these on the first run */
+ char *line = NULL;
+ size_t lineLen = 0, lineNum = 0;
char * const path = BarGetXdgConfigDir (configfiles[j]);
assert (path != NULL);
@@ -208,14 +212,59 @@ void BarSettingsRead (BarSettings_t *settings) {
}
while (1) {
- char lwhite, rwhite;
- int scanRet = fscanf (configfd, "%255s%c=%c%255[^\n]", key, &lwhite, &rwhite, val);
- if (scanRet == EOF) {
+ ++lineNum;
+ ssize_t ret = getline (&line, &lineLen, configfd);
+ if (ret == -1) {
+ /* EOF or error */
break;
- } else if (scanRet != 4 || lwhite != ' ' || rwhite != ' ') {
- /* invalid config line */
+ }
+ /* parse lines that match "^\s*(.*?)\s?=\s?(.*)$". Windows and Unix
+ * line terminators are supported. */
+ char *key = line;
+
+ /* skip leading spaces */
+ while (isspace ((unsigned char) key[0])) {
+ ++key;
+ }
+
+ /* skip comments */
+ if (key[0] == '#') {
continue;
}
+
+ /* search for delimiter and split key-value pair */
+ char *val = strchr (line, '=');
+ if (val == NULL) {
+ /* no warning for empty lines */
+ if (key[0] != '\0') {
+ BarUiMsg (settings, MSG_INFO,
+ "Invalid line at %s:%zu\n", path, lineNum);
+ }
+ /* invalid line */
+ continue;
+ }
+ *val = '\0';
+ ++val;
+
+ /* drop spaces at the end */
+ char *keyend = &key[strlen (key)-1];
+ while (keyend >= key && isspace ((unsigned char) *keyend)) {
+ *keyend = '\0';
+ --keyend;
+ }
+
+ /* strip at most one space, legacy cruft, required for values with
+ * leading spaces like love_icon */
+ if (isspace ((unsigned char) val[0])) {
+ ++val;
+ }
+ /* drop trailing cr/lf */
+ char *valend = &val[strlen (val)-1];
+ while (valend >= val && (*valend == '\r' || *valend == '\n')) {
+ *valend = '\0';
+ --valend;
+ }
+
if (streq ("control_proxy", key)) {
settings->controlProxy = strdup (val);
} else if (streq ("proxy", key)) {
@@ -350,11 +399,15 @@ void BarSettingsRead (BarSettings_t *settings) {
break;
}
}
+ } else {
+ BarUiMsg (settings, MSG_INFO,
+ "Unrecognized key %s at %s:%zu\n", key, path, lineNum);
}
}
fclose (configfd);
free (path);
+ free (line);
}
/* check environment variable if proxy is not set explicitly */