diff options
author | Lars-Dominik Braun <lars@6xq.net> | 2015-09-25 17:44:58 +0200 |
---|---|---|
committer | Lars-Dominik Braun <lars@6xq.net> | 2015-09-25 17:52:33 +0200 |
commit | 9dbd0f308b10f6a2982e72f25b0d26c951f5e87f (patch) | |
tree | 419e6f5d29449478ea869298c94fae66f6f458e1 | |
parent | 77ffe368e9b5045a801360c563623d5bc1c78771 (diff) | |
download | pianobar-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.1 | 4 | ||||
-rw-r--r-- | src/settings.c | 67 |
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 */ |