use own ini parsing
This commit is contained in:
parent
e97c0106ca
commit
286e0c5104
6
Makefile
6
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
|
||||
|
309
dunst.c
309
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[])
|
||||
|
176
ini.c
176
ini.c
@ -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 <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
83
ini.h
83
ini.h
@ -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 <stdio.h>
|
||||
|
||||
/* 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__ */
|
239
options.c
Normal file
239
options.c
Normal file
@ -0,0 +1,239 @@
|
||||
/* copyright 2012 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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: */
|
19
options.h
Normal file
19
options.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* copyright 2012 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
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: */
|
9
utils.c
9
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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user