diff --git a/Makefile b/Makefile index fb717f8..dcac48e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = draw.c dunst.c list.c dunst_dbus.c ini.c utils.c +SRC = draw.c dunst.c list.c dunst_dbus.c utils.c options.c OBJ = ${SRC:.c=.o} all: doc options dunst service @@ -24,9 +24,9 @@ config.h: @echo creating $@ from config.def.h @cp config.def.h $@ -dunst: draw.o dunst.o list.o dunst_dbus.o ini.o utils.o +dunst: draw.o dunst.o list.o dunst_dbus.o utils.o options.o @echo CC -o $@ - @${CC} ${CFLAGS} -o $@ dunst.o draw.o list.o dunst_dbus.o ini.o utils.o ${LDFLAGS} + @${CC} ${CFLAGS} -o $@ dunst.o draw.o list.o dunst_dbus.o options.o utils.o ${LDFLAGS} clean: @echo cleaning diff --git a/dunst.c b/dunst.c index 1f0451f..916db49 100644 --- a/dunst.c +++ b/dunst.c @@ -27,9 +27,12 @@ #include "draw.h" #include "dunst_dbus.h" #include "list.h" -#include "ini.h" #include "utils.h" +#ifndef STATIC_CONFIG +#include "options.h" +#endif + #define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh)) #define LENGTH(X) (sizeof X / sizeof X[0]) #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -357,7 +360,7 @@ void update_lists() int do_word_wrap(char *source, int max_width) { - strtrim_end(source); + rstrip(source); if (!source || strlen(source) == 0) return 0; @@ -402,7 +405,7 @@ int do_word_wrap(char *source, int max_width) void update_draw_txt_buf(notification * n, int max_width) { - strtrim_end(n->msg); + rstrip(n->msg); char *msg = n->msg; while(isspace(*msg)) msg++; @@ -1067,10 +1070,10 @@ void init_shortcut(keyboard_shortcut * ks) str++; *str = '\0'; str++; - strtrim_end(mod); + rstrip(mod); ks->mask = ks->mask | string_to_mask(mod); } - strtrim_end(str); + rstrip(str); ks->sym = XStringToKeysym(str); /* find matching keycode for ks->sym */ @@ -1477,26 +1480,6 @@ void parse_cmdline(int argc, char *argv[]) } #ifndef STATIC_CONFIG -static int dunst_ini_get_boolean(const char *value) -{ - switch (value[0]) { - case 'y': - case 'Y': - case 't': - case 'T': - case '1': - return True; - case 'n': - case 'N': - case 'f': - case 'F': - case '0': - return False; - default: - return False; - } -} - static rule_t *dunst_rules_find_or_create(const char *section) { l_node *iter; @@ -1518,158 +1501,6 @@ static rule_t *dunst_rules_find_or_create(const char *section) return rule; } -static char *dunst_ini_get_string(const char *value) -{ - char *s; - - if (value[0] == '"') - s = strdup(value + 1); - else - s = strdup(value); - - if (s[strlen(s) - 1] == '"') - s[strlen(s) - 1] = '\0'; - - return s; -} - -static int -dunst_ini_handle(void *user_data, const char *section, - const char *name, const char *value) -{ - if (strcmp(section, "global") == 0) { - if (strcmp(name, "font") == 0) - font = dunst_ini_get_string(value); - else if (strcmp(name, "format") == 0) - format = dunst_ini_get_string(value); - else if (strcmp(name, "sort") == 0) - sort = dunst_ini_get_boolean(value); - else if (strcmp(name, "indicate_hidden") == 0) - indicate_hidden = dunst_ini_get_boolean(value); - else if (strcmp(name, "word_wrap") == 0) - word_wrap = dunst_ini_get_boolean(value); - else if (strcmp(name, "idle_threshold") == 0) - idle_threshold = atoi(value); - else if (strcmp(name, "monitor") == 0) - scr.scr = atoi(value); - else if (strcmp(name, "follow") == 0) { - char *c = dunst_ini_get_string(value); - parse_follow_mode(c); - free(c); - } else if (strcmp(name, "geometry") == 0) - geom = dunst_ini_get_string(value); - else if (strcmp(name, "line_height") == 0) - line_height = atoi(value); - else if (strcmp(name, "modifier") == 0) { - deprecated_dunstrc_shortcuts = True; - char *c = dunst_ini_get_string(value); - KeySym mod = string_to_mask(c); - free(c); - close_ks.mask = mod; - close_all_ks.mask = mod; - history_ks.mask = mod; - } else if (strcmp(name, "key") == 0) { - close_ks.str = dunst_ini_get_string(value); - } else if (strcmp(name, "all_key") == 0) { - close_all_ks.str = dunst_ini_get_string(value); - } else if (strcmp(name, "history_key") == 0) { - history_ks.str = dunst_ini_get_string(value); - } else if (strcmp(name, "bounce_freq") == 0) { - bounce_freq = atof(value); - } else if (strcmp(name, "alignment") == 0) { - if (strcmp(value, "left") == 0) - align = left; - else if (strcmp(value, "center") == 0) - align = center; - else if (strcmp(value, "right") == 0) - align = right; - /* FIXME warning on unknown alignment */ - } else if (strcmp(name, "show_age_threshold") == 0) - show_age_threshold = atoi(value); - else if (strcmp(name, "sticky_history") == 0) - sticky_history = dunst_ini_get_boolean(value); - else if (strcmp(name, "separator_height") == 0) - separator_height = atoi(value); - else if (strcmp(name, "transparency") == 0) - transparency = atoi(value); - if (strcmp(name, "separator_color") == 0) { - char *str = dunst_ini_get_string(value); - if (strcmp(str, "auto") == 0) - sep_color = AUTO; - else if (strcmp(str, "foreground") == 0) - sep_color = FOREGROUND; - else - fprintf(stderr, "Warning: Unknown separator color\n"); - free(str); - } - } else if (strcmp(section, "urgency_low") == 0) { - if (strcmp(name, "background") == 0) - lowbgcolor = dunst_ini_get_string(value); - else if (strcmp(name, "foreground") == 0) - lowfgcolor = dunst_ini_get_string(value); - else if (strcmp(name, "timeout") == 0) - timeouts[LOW] = atoi(value); - - } else if (strcmp(section, "urgency_normal") == 0) { - if (strcmp(name, "background") == 0) - normbgcolor = dunst_ini_get_string(value); - else if (strcmp(name, "foreground") == 0) - normfgcolor = dunst_ini_get_string(value); - else if (strcmp(name, "timeout") == 0) - timeouts[NORM] = atoi(value); - - } else if (strcmp(section, "urgency_critical") == 0) { - if (strcmp(name, "background") == 0) - critbgcolor = dunst_ini_get_string(value); - else if (strcmp(name, "foreground") == 0) - critfgcolor = dunst_ini_get_string(value); - else if (strcmp(name, "timeout") == 0) - timeouts[CRIT] = atoi(value); - - } else if (strcmp(section, "shortcuts") == 0) { - if (strcmp(name, "close") == 0) - close_ks.str = dunst_ini_get_string(value); - else if (strcmp(name, "close_all") == 0) - close_all_ks.str = dunst_ini_get_string(value); - else if (strcmp(name, "history") == 0) - history_ks.str = dunst_ini_get_string(value); - } else { - - rule_t *current_rule = dunst_rules_find_or_create(section); - - if (strcmp(name, "appname") == 0) - current_rule->appname = dunst_ini_get_string(value); - else if (strcmp(name, "summary") == 0) - current_rule->summary = dunst_ini_get_string(value); - else if (strcmp(name, "body") == 0) - current_rule->body = dunst_ini_get_string(value); - else if (strcmp(name, "icon") == 0) - current_rule->icon = dunst_ini_get_string(value); - else if (strcmp(name, "timeout") == 0) - current_rule->timeout = atoi(value); - else if (strcmp(name, "urgency") == 0) { - const char *urg = value; - - if (strcmp(urg, "low") == 0) - current_rule->urgency = LOW; - else if (strcmp(urg, "normal") == 0) - current_rule->urgency = NORM; - else if (strcmp(urg, "critical") == 0) - current_rule->urgency = CRIT; - else - fprintf(stderr, - "unknown urgency: %s, ignoring\n", urg); - } else if (strcmp(name, "foreground") == 0) - current_rule->fg = dunst_ini_get_string(value); - else if (strcmp(name, "background") == 0) - current_rule->bg = dunst_ini_get_string(value); - else if (strcmp(name, "format") == 0) - current_rule->format = dunst_ini_get_string(value); - } - - return 1; -} - void parse_dunstrc(char *cmdline_config_path) { @@ -1695,14 +1526,132 @@ void parse_dunstrc(char *cmdline_config_path) } } - if (ini_parse_file(config_file, dunst_ini_handle, NULL) < 0) { - puts("dunstrc could not be parsed -> skipping\n"); + load_ini_file(config_file); + + font = ini_get_string("global", "font", font); + format = ini_get_string("global", "format", format); + sort = ini_get_bool("global", "sort", sort); + indicate_hidden = ini_get_bool("global", "indicate_hidden", indicate_hidden); + word_wrap = ini_get_bool("global", "word_wrap", word_wrap); + idle_threshold = ini_get_int("global", "idle_threshold", idle_threshold); + monitor = ini_get_int("global", "monitor", monitor); + { + char *c = ini_get_string("global", "follow", ""); + if (strlen(c) > 0) { + parse_follow_mode(c); + free(c); + } + } + geom = ini_get_string("global", "geometry", geom); + line_height = ini_get_int("global", "line_height", line_height); + { + char *c = ini_get_string("global", "modifier", ""); + if (strlen(c) > 0) { + deprecated_dunstrc_shortcuts = True; + KeySym mod = string_to_mask(c); + close_ks.mask = mod; + close_all_ks.mask = mod; + close_all_ks.mask = mod; + free(c); + } + } + close_ks.str = ini_get_string("global", "key", close_ks.str); + close_all_ks.str = ini_get_string("global", "key", close_all_ks.str); + history_ks.str = ini_get_string("global", "key", history_ks.str); + bounce_freq = ini_get_double("global", "bounce_freq", bounce_freq); + { + char *c = ini_get_string("global", "alignment", ""); + if (strlen(c) > 0) { + if (strcmp(c, "left") == 0) + align = left; + else if (strcmp(c, "center") == 0) + align = center; + else if (strcmp(c, "right") == 0) + align = right; + else + fprintf(stderr, "Warning: unknown allignment\n"); + free(c); + } + } + show_age_threshold = ini_get_int("global", "show_age_threshold", show_age_threshold); + sticky_history = ini_get_bool("global", "sticky_history", sticky_history); + separator_height = ini_get_int("global", "separator_height", separator_height); + transparency = ini_get_int("global", "transparency", transparency); + { + char *c = ini_get_string("global", "separator_color", ""); + if (strlen(c) > 0) { + if (strcmp(c, "auto") == 0) + sep_color = AUTO; + else if (strcmp(c, "foreground") == 0) + sep_color = FOREGROUND; + else + fprintf(stderr, "Warning: Unknown separator color\n"); + free(c); + } + } + + lowbgcolor = ini_get_string("urgency_low", "background", lowbgcolor); + lowfgcolor = ini_get_string("urgency_low", "foreground", lowfgcolor); + timeouts[LOW] = ini_get_int("urgency_low", "timeout", timeouts[LOW]); + normbgcolor = ini_get_string("urgency_normal", "background", normbgcolor); + normfgcolor = ini_get_string("urgency_normal", "foreground", normfgcolor); + timeouts[NORM] = ini_get_int("urgency_normal", "timeout", timeouts[NORM]); + critbgcolor = ini_get_string("urgency_critical", "background", critbgcolor); + critfgcolor = ini_get_string("urgency_critical", "foreground", critfgcolor); + timeouts[CRIT] = ini_get_int("urgency_critical", "timeout", timeouts[CRIT]); + + close_ks.str = ini_get_string("shortcuts", "close", close_ks.str); + close_all_ks.str = ini_get_string("shortcuts", "close_all", close_all_ks.str); + history_ks.str = ini_get_string("shortcuts", "history", history_ks.str); + + + char *cur_section = NULL; + for (; cur_section; cur_section = next_section(cur_section)) { + if (strcmp(cur_section, "global") == 0 + || strcmp(cur_section, "shortcuts") == 0 + || strcmp(cur_section, "urgency_low") == 0 + || strcmp(cur_section, "urgency_normal") == 0 + || strcmp(cur_section, "urgency_critical") == 0) + continue; + + rule_t *current_rule = dunst_rules_find_or_create(cur_section); + current_rule->appname = ini_get_string( + cur_section, "appname", current_rule->appname); + current_rule->summary = ini_get_string( + cur_section, "summary", current_rule->summary); + current_rule->body = ini_get_string( + cur_section, "body", current_rule->body); + current_rule->icon = ini_get_string( + cur_section, "icon", current_rule->icon); + current_rule->timeout = ini_get_int( + cur_section, "timeout", current_rule->timeout); + { + char *urg = ini_get_string(cur_section, "urgency", ""); + if (strlen(urg) > 0) { + if (strcmp(urg, "low") == 0) + current_rule->urgency = LOW; + else if (strcmp(urg, "normal") == 0) + current_rule->urgency = NORM; + else if (strcmp(urg, "critical") == 0) + current_rule->urgency = CRIT; + else + fprintf(stderr, + "unknown urgency: %s, ignoring\n", urg); + free(urg); + } + } + current_rule->fg = ini_get_string( + cur_section, "foreground", current_rule->fg); + current_rule->bg = ini_get_string( + cur_section, "background", current_rule->bg); + current_rule->format = ini_get_string( + cur_section, "format", current_rule->format); } fclose(config_file); xdgWipeHandle(&xdg); - } + #endif /* STATIC_CONFIG */ char *parse_cmdline_for_config_file(int argc, char *argv[]) diff --git a/ini.c b/ini.c deleted file mode 100644 index a90df81..0000000 --- a/ini.c +++ /dev/null @@ -1,176 +0,0 @@ -/* inih -- simple .INI file parser - -inih is released under the New BSD license. Go to the project -home page for more info: - -The "inih" library is distributed under the New BSD license: - -Copyright (c) 2009, Brush Technology -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Brush Technology nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -http://code.google.com/p/inih/ - -*/ - -#include -#include -#include - -#include "ini.h" - -#define MAX_LINE 200 -#define MAX_SECTION 50 -#define MAX_NAME 50 - -/* Strip whitespace chars off end of given string, in place. Return s. */ -static char* rstrip(char* s) -{ - char* p = s + strlen(s); - while (p > s && isspace(*--p)) - *p = '\0'; - return s; -} - -/* Return pointer to first non-whitespace char in given string. */ -static char* lskip(const char* s) -{ - while (*s && isspace(*s)) - s++; - return (char*)s; -} - -/* Return pointer to first char c or ';' comment in given string, or pointer to - null at end of string if neither found. ';' must be prefixed by a whitespace - character to register as a comment. */ -static char* find_char_or_comment(const char* s, char c) -{ - int was_whitespace = 0; - while (*s && *s != c && !(was_whitespace && *s == ';')) { - was_whitespace = isspace(*s); - s++; - } - return (char*)s; -} - -/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ -static char* strncpy0(char* dest, const char* src, size_t size) -{ - strncpy(dest, src, size); - dest[size - 1] = '\0'; - return dest; -} - -/* See documentation in header file. */ -int ini_parse_file(FILE* file, - int (*handler)(void*, const char*, const char*, - const char*), - void* user) -{ - /* Uses a fair bit of stack (use heap instead if you need to) */ - char line[MAX_LINE]; - char section[MAX_SECTION] = ""; - char prev_name[MAX_NAME] = ""; - - char* start; - char* end; - char* name; - char* value; - int lineno = 0; - int error = 0; - - /* Scan through file line by line */ - while (fgets(line, sizeof(line), file) != NULL) { - lineno++; - start = lskip(rstrip(line)); - - if (*start == ';' || *start == '#') { - /* Per Python ConfigParser, allow '#' comments at start of line */ - } -#if INI_ALLOW_MULTILINE - else if (*prev_name && *start && start > line) { - /* Non-black line with leading whitespace, treat as continuation - of previous name's value (as per Python ConfigParser). */ - if (!handler(user, section, prev_name, start) && !error) - error = lineno; - } -#endif - else if (*start == '[') { - /* A "[section]" line */ - end = find_char_or_comment(start + 1, ']'); - if (*end == ']') { - *end = '\0'; - strncpy0(section, start + 1, sizeof(section)); - *prev_name = '\0'; - } - else if (!error) { - /* No ']' found on section line */ - error = lineno; - } - } - else if (*start && *start != ';') { - /* Not a comment, must be a name[=:]value pair */ - end = find_char_or_comment(start, '='); - if (*end != '=') { - end = find_char_or_comment(start, ':'); - } - if (*end == '=' || *end == ':') { - *end = '\0'; - name = rstrip(start); - value = lskip(end + 1); - end = find_char_or_comment(value, '\0'); - if (*end == ';') - *end = '\0'; - rstrip(value); - - /* Valid name[=:]value pair found, call handler */ - strncpy0(prev_name, name, sizeof(prev_name)); - if (!handler(user, section, name, value) && !error) - error = lineno; - } - else if (!error) { - /* No '=' or ':' found on name[=:]value line */ - error = lineno; - } - } - } - - return error; -} - -/* See documentation in header file. */ -int ini_parse(const char* filename, - int (*handler)(void*, const char*, const char*, const char*), - void* user) -{ - FILE* file; - int error; - - file = fopen(filename, "r"); - if (!file) - return -1; - error = ini_parse_file(file, handler, user); - fclose(file); - return error; -} diff --git a/ini.h b/ini.h deleted file mode 100644 index 3c76654..0000000 --- a/ini.h +++ /dev/null @@ -1,83 +0,0 @@ -/* inih -- simple .INI file parser - -inih is released under the New BSD license. Go to the project -home page for more info: - -The "inih" library is distributed under the New BSD license: - -Copyright (c) 2009, Brush Technology -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Brush Technology nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -http://code.google.com/p/inih/ - -*/ - -#ifndef __INI_H__ -#define __INI_H__ - -/* Make this header file easier to include in C++ code */ -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* Parse given INI-style file. May have [section]s, name=value pairs - (whitespace stripped), and comments starting with ';' (semicolon). Section - is "" if name=value pair parsed before any section heading. name:value - pairs are also supported as a concession to Python's ConfigParser. - - For each name=value pair parsed, call handler function with given user - pointer as well as section, name, and value (data only valid for duration - of handler call). Handler should return nonzero on success, zero on error. - - Returns 0 on success, line number of first error on parse error (doesn't - stop on first error), or -1 on file open error. -*/ -int ini_parse(const char* filename, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); - -/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't - close the file when it's finished -- the caller must do that. */ -int ini_parse_file(FILE* file, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); - -/* Nonzero to allow multi-line value parsing, in the style of Python's - ConfigParser. If allowed, ini_parse() will call the handler with the same - name for each subsequent line parsed. */ -#ifndef INI_ALLOW_MULTILINE -#define INI_ALLOW_MULTILINE 1 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __INI_H__ */ diff --git a/options.c b/options.c new file mode 100644 index 0000000..20c13cc --- /dev/null +++ b/options.c @@ -0,0 +1,239 @@ +/* copyright 2012 Sascha Kruse and contributors (see LICENSE for licensing information) */ +#include +#include +#include +#include +#include + +#include "options.h" +#include "utils.h" + +typedef struct _entry_t { + char *key; + char *value; +} entry_t; + +typedef struct _section_t { + char *name; + int entry_count; + entry_t *entries; +} section_t; + + + + + +static int section_count; +static section_t *sections; + +static section_t *new_section(char *name); +static section_t *get_section(char *name); +static void add_entry(char *section_name, char *key, char *value); +static char *get_value(char *section, char *key); +static char *clean_value(char *value); + +section_t *new_section(char *name) +{ + section_count++; + sections = realloc(sections, sizeof(section_t) *section_count); + sections[section_count - 1].name = strdup(name); + sections[section_count - 1].entries = NULL; + sections[section_count - 1].entry_count = 0; + return §ions[section_count -1]; +} + +section_t *get_section(char *name) +{ + for (int i = 0; i < section_count; i++) { + if (strcmp(sections[i].name, name) == 0) + return §ions[i]; + } + + return NULL; +} + +void add_entry(char *section_name, char *key, char *value) +{ + section_t *s = get_section(section_name); + if (s == NULL) { + s = new_section(section_name); + } + + s->entry_count++; + int len = s->entry_count; + s->entries = realloc(s->entries, sizeof(entry_t) * len); + s->entries[s->entry_count - 1].key = strdup(key); + s->entries[s->entry_count - 1].value = clean_value(value); +} + +char *get_value(char *section, char *key) +{ + section_t *s = get_section(section); + if (!s) { + return NULL; + } + + for (int i = 0; i < s->entry_count; i++) { + if (strcmp(s->entries[i].key, key) == 0) { + return s->entries[i].value; + } + } + return NULL; +} + +char *ini_get_string(char *section, char *key, const char *def) +{ + char *value = get_value(section, key); + if (value == NULL) + return def; + else + return strdup(value); +} + +int ini_get_int(char *section, char *key, int def) +{ + char *value = get_value(section, key); + if (value == NULL) + return def; + else + return atoi(value); +} + +double ini_get_double(char *section, char *key, int def) +{ + char *value = get_value(section, key); + if (value == NULL) + return def; + else + return atof(value); +} + +char *next_section(char *section) +{ + if (section_count == 0) + return NULL; + + for (int i = 0; i < section_count; i++) { + if (strcmp(section, sections[i].name) == 0) { + if (i + 1 >= section_count) + return NULL; + else + return sections[i+1].name; + } + } + return NULL; +} + +int ini_get_bool(char *section, char *key, int def) +{ + char *value = get_value(section, key); + if (value == NULL) + return def; + else { + switch (value[0]) { + case 'y': + case 'Y': + case 't': + case 'T': + case '1': + return true; + case 'n': + case 'N': + case 'f': + case 'F': + case '0': + return false; + default: + return false; + } + } +} + +char *clean_value(char *value) +{ + char *s; + + if (value[0] == '"') + s = strdup(value + 1); + else + s = strdup(value); + + if (s[strlen(s) - 1] == '"') + s[strlen(s) - 1] = '\0'; + + return s; + +} + +int load_ini_file(FILE *fp) +{ + char line[BUFSIZ]; + + int line_num = 0; + char *current_section = NULL; + while (fgets(line, sizeof(line), fp) != NULL) { + line_num++; + + char *start = lskip(rstrip(line)); + + if (*start == ';' || *start == '#' || strlen(start) == 0) + continue; + + if (*start == '[') { + char *end = strstr(start + 1, "]"); + if (!end) { + printf("Warning: invalid config file at line %d\n", line_num); + printf("Missing ']'\n"); + continue; + } + + *end = '\0'; + + if (current_section) + free(current_section); + current_section = (strdup(start+1)); + new_section(strdup(current_section)); + continue; + } + + char *equal = strstr(start + 1, "="); + if (!equal) { + printf("Warning: invalid config file at line %d\n", line_num); + printf("Missing '='\n"); + continue; + } + + *equal = '\0'; + char *key = rstrip(start); + char *value = lskip(equal+1); + + char *quote = strstr(value, "\""); + if (quote) { + char *closing_quote = strstr(quote + 1, "\""); + if (!closing_quote) { + printf("Warning: invalid config file at line %d\n", line_num); + printf("Missing '\"'\n"); + continue; + } + + closing_quote = '\0'; + } else { + char *comment = strstr(value, "#"); + if (!comment) + comment = strstr(value, ";"); + if (comment) + comment = '\0'; + } + value = rstrip(value); + + if (!current_section) { + printf("Warning: invalid config file at line: %d\n", line_num); + printf("Key value pair without a section\n"); + continue; + } + + add_entry(current_section, key, value); + } + return 0; +} +/* vim: set ts=8 sw=8 tw=0: */ diff --git a/options.h b/options.h new file mode 100644 index 0000000..b4beafd --- /dev/null +++ b/options.h @@ -0,0 +1,19 @@ +/* copyright 2012 Sascha Kruse and contributors (see LICENSE for licensing information) */ +#pragma once + +#include + + +int load_ini_file(FILE *); +char *ini_get_string(char *section, char *key, const char *def); +int ini_get_int(char *section, char *key, int def); +double ini_get_double(char *section, char *key, int def); +int ini_get_bool(char *section, char *key, int def); + +/* returns the next known section. + * if section == NULL returns first section. + * returns NULL if no more sections are available + */ +char *next_section(char *section); + +/* vim: set ts=8 sw=8 tw=0: */ diff --git a/utils.c b/utils.c index ae5854f..e587429 100644 --- a/utils.c +++ b/utils.c @@ -7,7 +7,7 @@ #include "dunst.h" -void strtrim_end(char *str) +char *rstrip(char *str) { char *end; end = str + strlen(str) - 1; @@ -15,6 +15,13 @@ void strtrim_end(char *str) *end = '\0'; end--; } + return str; +} + +char *lskip(char *s) +{ + for(; *s && isspace(*s); s++); + return s; } char *string_replace(const char *needle, const char *replacement, diff --git a/utils.h b/utils.h index bde4408..8995b01 100644 --- a/utils.h +++ b/utils.h @@ -1,7 +1,8 @@ #ifndef UTIL_H #define UTIL_H /* remove spaces before and after str */ -void strtrim_end(char *str); +char *rstrip(char *str); +char *lskip(char *str); /* replace needle with replacement in haystack */ char *string_replace(const char *needle, const char *replacement,