Merge branch 'master' of github.com:knopwob/dunst
This commit is contained in:
commit
eb5e8fb537
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
|
||||
|
@ -119,6 +119,8 @@ fmt is a string containing placeholders. The placeholders will be replaced with
|
||||
|
||||
=item B<%I> iconname (without its path)
|
||||
|
||||
=item B<%p> progress value ([ 0%] to [100%])
|
||||
|
||||
=back
|
||||
|
||||
=head1 COLORS
|
||||
@ -131,6 +133,7 @@ X color names.
|
||||
|
||||
dunst is able to get different colors for a message via notify-send.
|
||||
In order to do that you have to add a hint via the -h option.
|
||||
The progress value can be set with a hint, too.
|
||||
|
||||
=over 4
|
||||
|
||||
@ -138,6 +141,8 @@ In order to do that you have to add a hint via the -h option.
|
||||
|
||||
=item notify-send -h string:bgcolor:#4444ff -h string:fgcolor:#ff4444
|
||||
|
||||
=item notify-send -h int:value:42 "Working ..."
|
||||
|
||||
=back
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
401
dunst.c
401
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))
|
||||
@ -185,14 +188,15 @@ void warn(const char *text, int urg)
|
||||
if (n == NULL)
|
||||
die("Unable to allocate memory", EXIT_FAILURE);
|
||||
|
||||
n->appname = "dunst";
|
||||
n->appname = strdup("dunst");
|
||||
n->summary = strdup(text);
|
||||
if (n->summary == NULL)
|
||||
die("Unable to allocate memory", EXIT_FAILURE);
|
||||
n->body = "";
|
||||
n->icon = "";
|
||||
n->body = strdup("");
|
||||
n->icon = strdup("");
|
||||
n->timeout = 0;
|
||||
n->urgency = urg;
|
||||
n->progress = 0;
|
||||
n->dbus_client = NULL;
|
||||
n->color_strings[ColFG] = NULL;
|
||||
n->color_strings[ColBG] = NULL;
|
||||
@ -338,7 +342,12 @@ void update_lists()
|
||||
}
|
||||
|
||||
to_move = most_important(notification_queue);
|
||||
if (!to_move) {
|
||||
return;
|
||||
}
|
||||
n = (notification *) to_move->data;
|
||||
if (!n)
|
||||
return;
|
||||
n->start = now;
|
||||
|
||||
/* TODO get notifications pushed back into
|
||||
@ -357,7 +366,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,39 +411,30 @@ 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++;
|
||||
|
||||
if (!n->draw_txt_buf.txt) {
|
||||
int dup_len = strlen(" () ") + digit_count(INT_MAX);
|
||||
int msg_len = strlen(msg) + 2; /* 2 == surrounding spaces */
|
||||
int age_len = strlen(" ( h 60m 60s old ) ")
|
||||
+ digit_count(INT_MAX); /* could be INT_MAX hours */
|
||||
int line_length = dup_len + msg_len + age_len;
|
||||
if (n->draw_txt_buf.txt)
|
||||
free(n->draw_txt_buf.txt);
|
||||
|
||||
line_length += sizeof(" ( more ) ") + digit_count(INT_MAX);
|
||||
|
||||
n->draw_txt_buf.txt = calloc(line_length, sizeof(char));
|
||||
n->draw_txt_buf.bufsize = line_length;
|
||||
}
|
||||
|
||||
char *buf = n->draw_txt_buf.txt;
|
||||
int bufsize = n->draw_txt_buf.bufsize;
|
||||
char *next = buf;
|
||||
|
||||
memset(buf, '\0', bufsize);
|
||||
char *buf;
|
||||
|
||||
/* print dup_count */
|
||||
if (n->dup_count > 0) {
|
||||
snprintf(next, bufsize - strlen(buf), "(%d) ", n->dup_count);
|
||||
next = buf + strlen(buf);
|
||||
asprintf(&buf, "(%d)", n->dup_count);
|
||||
} else {
|
||||
buf = strdup("");
|
||||
}
|
||||
|
||||
/* print msg */
|
||||
strncat(buf, msg, bufsize - strlen(buf));
|
||||
next = buf + strlen(buf);
|
||||
{
|
||||
char *new_buf;
|
||||
asprintf(&new_buf, "%s %s", buf, msg);
|
||||
free(buf);
|
||||
buf = new_buf;
|
||||
}
|
||||
|
||||
/* print age */
|
||||
int hours, minutes, seconds;
|
||||
@ -445,20 +445,22 @@ void update_draw_txt_buf(notification * n, int max_width)
|
||||
minutes = t_delta / 60 % 60;
|
||||
seconds = t_delta % 60;
|
||||
|
||||
char *new_buf;
|
||||
if (hours > 0) {
|
||||
snprintf(next, bufsize - strlen(buf),
|
||||
" (%dh %dm %ds old)", hours, minutes, seconds);
|
||||
asprintf(&new_buf, "%s (%dh %dm %ds old)", buf, hours,
|
||||
minutes, seconds);
|
||||
} else if (minutes > 0) {
|
||||
snprintf(next, bufsize - strlen(buf), " (%dm %ds old)",
|
||||
minutes, seconds);
|
||||
asprintf(&new_buf, "%s (%dm %ds old)", buf, minutes, seconds);
|
||||
} else {
|
||||
snprintf(next, bufsize - strlen(buf), " (%ds old)",
|
||||
seconds);
|
||||
asprintf(&new_buf, "%s (%ds old)", buf, seconds);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
buf = new_buf;
|
||||
}
|
||||
|
||||
n->draw_txt_buf.line_count =
|
||||
do_word_wrap(n->draw_txt_buf.txt, max_width);
|
||||
n->draw_txt_buf.line_count = do_word_wrap(buf, max_width);
|
||||
n->draw_txt_buf.txt = buf;
|
||||
}
|
||||
|
||||
char *draw_txt_get_line(draw_txt * dt, int line)
|
||||
@ -907,6 +909,13 @@ int init_notification(notification * n, int id)
|
||||
n->msg = string_replace("%i", n->icon, n->msg);
|
||||
n->msg = string_replace("%I", basename(n->icon), n->msg);
|
||||
n->msg = string_replace("%b", n->body, n->msg);
|
||||
if (n->progress) {
|
||||
char pg[10];
|
||||
sprintf(pg, "[%3d%%]", n->progress-1);
|
||||
n->msg = string_replace("%p", pg, n->msg);
|
||||
} else {
|
||||
n->msg = string_replace("%p", "", n->msg);
|
||||
}
|
||||
|
||||
n->msg = fix_markup(n->msg);
|
||||
|
||||
@ -917,7 +926,7 @@ int init_notification(notification * n, int id)
|
||||
/* check if n is a duplicate */
|
||||
for (l_node * iter = notification_queue->head; iter; iter = iter->next) {
|
||||
notification *orig = (notification *) iter->data;
|
||||
if (strcmp(orig->msg, n->msg) == 0) {
|
||||
if (strcmp(orig->appname, n->appname) == 0 && strcmp(orig->msg, n->msg) == 0) {
|
||||
orig->dup_count++;
|
||||
free_notification(n);
|
||||
return orig->id;
|
||||
@ -927,7 +936,7 @@ int init_notification(notification * n, int id)
|
||||
for (l_node * iter = displayed_notifications->head; iter;
|
||||
iter = iter->next) {
|
||||
notification *orig = (notification *) iter->data;
|
||||
if (strcmp(orig->msg, n->msg) == 0) {
|
||||
if (strcmp(orig->appname, n->appname) == 0 && strcmp(orig->msg, n->msg) == 0) {
|
||||
orig->dup_count++;
|
||||
orig->start = now;
|
||||
free_notification(n);
|
||||
@ -963,6 +972,7 @@ int init_notification(notification * n, int id)
|
||||
n->id = ++next_notification_id;
|
||||
} else {
|
||||
close_notification_by_id(id, -1);
|
||||
n->id = id;
|
||||
}
|
||||
|
||||
if(strlen(n->msg) == 0) {
|
||||
@ -1067,10 +1077,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 */
|
||||
@ -1079,10 +1089,9 @@ void init_shortcut(keyboard_shortcut * ks)
|
||||
|
||||
ks->code = NoSymbol;
|
||||
|
||||
int level = ks->mask & ShiftMask ? 1 : 0;
|
||||
|
||||
for (int i = min_keysym; i <= max_keysym; i++) {
|
||||
if (XkbKeycodeToKeysym(dc->dpy, i, 0, level) == ks->sym) {
|
||||
if (XkbKeycodeToKeysym(dc->dpy, i, 0, 0) == ks->sym
|
||||
|| XkbKeycodeToKeysym(dc->dpy, i, 0, 1) == ks->sym) {
|
||||
ks->code = i;
|
||||
break;
|
||||
}
|
||||
@ -1195,6 +1204,7 @@ int select_screen(XineramaScreenInfo * info, int info_len)
|
||||
|
||||
} else {
|
||||
int x, y;
|
||||
assert(f_mode == FOLLOW_MOUSE || f_mode == FOLLOW_KEYBOARD);
|
||||
Window root = RootWindow(dc->dpy, DefaultScreen(dc->dpy));
|
||||
|
||||
if (f_mode == FOLLOW_MOUSE) {
|
||||
@ -1239,10 +1249,9 @@ void update_screen_info()
|
||||
{
|
||||
#ifdef XINERAMA
|
||||
int n;
|
||||
int screen = scr.scr;
|
||||
XineramaScreenInfo *info;
|
||||
if ((info = XineramaQueryScreens(dc->dpy, &n))) {
|
||||
screen = select_screen(info, n);
|
||||
int screen = select_screen(info, n);
|
||||
if (screen >= n) {
|
||||
/* invalid monitor, fallback to default */
|
||||
screen = 0;
|
||||
@ -1296,7 +1305,7 @@ void setup(void)
|
||||
DefaultScreen(dc->dpy)),
|
||||
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
|
||||
transparency = transparency > 100 ? 100 : transparency;
|
||||
setopacity(dc, win, (unsigned long)((100 - transparency) * (0xffffffff/100)));
|
||||
setopacity(dc, win, (unsigned long)((100 - transparency) * (0xffffffff/100)));
|
||||
grab_key(&history_ks);
|
||||
}
|
||||
|
||||
@ -1477,26 +1486,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 +1507,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,15 +1532,136 @@ 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 = next_section(cur_section);
|
||||
if (!cur_section)
|
||||
break;
|
||||
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);
|
||||
free_ini();
|
||||
xdgWipeHandle(&xdg);
|
||||
|
||||
}
|
||||
#endif /* STATIC_CONFIG */
|
||||
|
||||
|
||||
char *parse_cmdline_for_config_file(int argc, char *argv[])
|
||||
{
|
||||
@ -1718,6 +1676,7 @@ char *parse_cmdline_for_config_file(int argc, char *argv[])
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif /* STATIC_CONFIG */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
2
dunst.h
2
dunst.h
@ -33,7 +33,6 @@ typedef struct _screen_info {
|
||||
typedef struct _draw_txt {
|
||||
char *txt;
|
||||
int line_count;
|
||||
int bufsize;
|
||||
} draw_txt;
|
||||
|
||||
typedef struct _notification {
|
||||
@ -54,6 +53,7 @@ typedef struct _notification {
|
||||
int dup_count;
|
||||
ColorSet *colors;
|
||||
char *color_strings[2];
|
||||
int progress; /* percentage + 1, 0 to hide */
|
||||
} notification;
|
||||
|
||||
typedef struct _notification_buffer {
|
||||
|
14
dunst_dbus.c
14
dunst_dbus.c
@ -20,7 +20,7 @@ static void _extract_basic(int type, DBusMessageIter * iter, void *target)
|
||||
}
|
||||
|
||||
static void
|
||||
_extract_hint(const char *name, const char *hint_name,
|
||||
_extract_hint(int type, const char *name, const char *hint_name,
|
||||
DBusMessageIter * hint, void *target)
|
||||
{
|
||||
|
||||
@ -30,7 +30,7 @@ _extract_hint(const char *name, const char *hint_name,
|
||||
dbus_message_iter_next(hint);
|
||||
dbus_message_iter_recurse(hint, &hint_value);
|
||||
do {
|
||||
dbus_message_iter_get_basic(&hint_value, target);
|
||||
_extract_basic(type, &hint_value, target);
|
||||
} while (dbus_message_iter_next(hint));
|
||||
}
|
||||
}
|
||||
@ -296,6 +296,7 @@ void notify(DBusMessage * dmsg)
|
||||
const char *fgcolor = NULL;
|
||||
const char *bgcolor = NULL;
|
||||
int urgency = 1;
|
||||
int progress = -1;
|
||||
notification *n = malloc(sizeof(notification));
|
||||
dbus_uint32_t replaces_id = 0;
|
||||
dbus_int32_t expires = -1;
|
||||
@ -335,9 +336,11 @@ void notify(DBusMessage * dmsg)
|
||||
continue;
|
||||
}
|
||||
dbus_message_iter_get_basic(&hint, &hint_name);
|
||||
_extract_hint("urgency", hint_name, &hint, &urgency);
|
||||
_extract_hint("fgcolor", hint_name, &hint, &fgcolor);
|
||||
_extract_hint("bgcolor", hint_name, &hint, &bgcolor);
|
||||
_extract_hint(DBUS_TYPE_BYTE, "urgency", hint_name, &hint, &urgency);
|
||||
_extract_hint(DBUS_TYPE_STRING, "fgcolor", hint_name, &hint, &fgcolor);
|
||||
_extract_hint(DBUS_TYPE_STRING, "bgcolor", hint_name, &hint, &bgcolor);
|
||||
_extract_hint(DBUS_TYPE_INT32, "value", hint_name, &hint, &progress);
|
||||
if (!progress) _extract_hint(DBUS_TYPE_UINT32, "value", hint_name, &hint, &progress);
|
||||
dbus_message_iter_next(&hint);
|
||||
}
|
||||
dbus_message_iter_next(&hints);
|
||||
@ -355,6 +358,7 @@ void notify(DBusMessage * dmsg)
|
||||
n->body = body != NULL ? strdup(body) : "";
|
||||
n->icon = icon != NULL ? strdup(icon) : "";
|
||||
n->timeout = expires;
|
||||
n->progress = (progress < 0 || progress > 100) ? 0 : progress+1;
|
||||
n->urgency = urgency;
|
||||
n->dbus_client = strdup(dbus_message_get_sender(dmsg));
|
||||
for (i = 0; i < ColLast; i++) {
|
||||
|
1
dunstrc
1
dunstrc
@ -7,6 +7,7 @@
|
||||
# %b body
|
||||
# %i iconname (including its path)
|
||||
# %I iconname (without its path)
|
||||
# %p progress value if set ([ 0%] to [100%]) or nothing
|
||||
format = "%s %b"
|
||||
|
||||
# Sort messages by urgency
|
||||
|
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__ */
|
258
options.c
Normal file
258
options.c
Normal file
@ -0,0 +1,258 @@
|
||||
/* 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];
|
||||
}
|
||||
|
||||
void free_ini(void)
|
||||
{
|
||||
for(int i = 0; i < section_count; i++) {
|
||||
for (int j = 0; j < sections[i].entry_count; j++) {
|
||||
free(sections[i].entries[j].key);
|
||||
free(sections[i].entries[j].value);
|
||||
}
|
||||
free(sections[i].entries);
|
||||
free(sections[i].name);
|
||||
}
|
||||
free(sections);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (section == NULL) {
|
||||
return sections[0].name;
|
||||
}
|
||||
|
||||
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(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);
|
||||
}
|
||||
if (current_section)
|
||||
free(current_section);
|
||||
return 0;
|
||||
}
|
||||
/* vim: set ts=8 sw=8 tw=0: */
|
20
options.h
Normal file
20
options.h
Normal file
@ -0,0 +1,20 @@
|
||||
/* 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);
|
||||
void free_ini(void);
|
||||
|
||||
/* 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