Merge branch 'next'

This commit is contained in:
Sascha Kruse 2012-12-19 17:45:07 +01:00
commit 67774c3e46
17 changed files with 1379 additions and 1111 deletions

View File

@ -3,7 +3,7 @@
include config.mk
SRC = draw.c dunst.c list.c dunst_dbus.c utils.c options.c
SRC = draw.c dunst.c container.c dunst_dbus.c utils.c options.c
OBJ = ${SRC:.c=.o}
all: doc options dunst service
@ -24,9 +24,13 @@ config.h:
@echo creating $@ from config.def.h
@cp config.def.h $@
dunst: draw.o dunst.o list.o dunst_dbus.o utils.o options.o
dunst: ${OBJ}
@echo CC -o $@
@${CC} ${CFLAGS} -o $@ dunst.o draw.o list.o dunst_dbus.o options.o utils.o ${LDFLAGS}
@${CC} ${CFLAGS} -o $@ ${OBJ} ${LDFLAGS}
debug: ${OBJ}
@echo CC -o $@
@${CC} ${CFLAGS} -O0 -o dunst ${OBJ} ${LDFLAGS}
clean:
@echo cleaning
@ -34,6 +38,7 @@ clean:
@rm -f dunst
@rm -f dunst.1
@rm -f org.knopwob.dunst.service
@rm -f core
doc: dunst.1
dunst.1: README.pod

View File

@ -145,6 +145,21 @@ The progress value can be set with a hint, too.
=back
=head1 MISCELLANEOUS
Dunst can be paused by sending a notification with a summary of "DUNST_COMMAND_PAUSE"
and resumed with a summary of "DUNST_COMMAND_RESUME". Alternatively you can send SIGUSR1 and SIGUSR2 to pause and unpause respectivly. For Example:
=item killall -SIGUSR1 dunst # pause
=item killall -SIGUSR2 dunst # resume
=back
When paused dunst will not display any notifications but keep all notifications in a queue.
This can for example be wrapped around a screen locker (i3lock, slock) to prevent flickering
of notifications through the lock and to read all missed notifications after returning to the computer.
=head1 CONFIGURATION
An example configuration file is included (usually /usr/share/dunst/dunstrc).

View File

@ -27,10 +27,21 @@ int line_height = 0; /* if line height < font height, it will be raised to fon
int separator_height = 2; /* height of the separator line between two notifications */
enum separator_color sep_color = AUTO; /* AUTO or FOREGROUND */
/* show a notification on startup
* This is mainly for crash detection since dbus restarts dunst
* automatically after a crash, so crashes might get unnotices otherwise
* */
int startup_notification = False;
/* monitor to display notifications on */
int monitor = 0;
/* path to dmenu */
char *dmenu = "/usr/bin/dmenu";
char *browser = "/usr/bin/firefox";
/* follow focus to different monitor and display notifications there?
* possible values:
* FOLLOW_NONE
@ -54,6 +65,9 @@ keyboard_shortcut close_all_ks = {.str = "none",
keyboard_shortcut history_ks = {.str = "none",
.code = 0, .sym = NoSymbol,.is_valid = False}; /* ignore this */
keyboard_shortcut context_ks = {.str = "none",
.code = 0, .sym = NoSymbol,.is_valid = False}; /* ignore this */
rule_t default_rules[] = {
/* name can be any unique string. It is used to identify the rule in dunstrc to override it there */

177
container.c Normal file
View File

@ -0,0 +1,177 @@
#include "stdlib.h"
#include "stdio.h"
#include <string.h>
#include "container.h"
void n_stack_push(n_stack **s, notification *n)
{
if (!n || !s)
return;
n_stack *new = malloc(sizeof(n_stack));
new->n = n;
new->next = *s;
*s = new;
}
notification *n_stack_pop(n_stack **s)
{
if (!s || !*s)
return NULL;
n_stack *head = *s;
*s = (*s)->next;
notification *n = head->n;
free(head);
return n;
}
void n_stack_remove(n_stack **s, notification *n)
{
if (!s || !*s || !n)
return;
/* head is n */
if ((*s)->n == n) {
n_stack *tmp = *s;
*s = (*s)->next;
free(tmp);
return;
}
for (n_stack *iter = *s; iter->next; iter = iter->next) {
if (iter->next->n == n) {
n_stack *tmp = iter->next;
iter->next = iter->next->next;
free(tmp);
return;
}
}
}
int n_stack_len(n_stack **s)
{
if (!s || !*s)
return 0;
n_stack *cur = *s;
int count = 0;
while (cur) {
cur = cur->next;
count++;
}
return count;
}
int cmp_notification(notification *a, notification *b)
{
if (a == NULL && b == NULL)
return 0;
else if (a == NULL)
return -1;
else if (b == NULL)
return 1;
if (a->urgency != b->urgency) {
return a->urgency - b->urgency;
} else {
return b->timestamp - a->timestamp;
}
}
void n_queue_enqueue(n_queue **q, notification *n)
{
if (!n || !q)
return;
n_queue *new = malloc(sizeof(n_queue));
new->n = n;
new->next = NULL;
if (!(*q)) {
/* queue was empty */
*q = new;
return;
}
/* new head */
if (cmp_notification(new->n, (*q)->n) > 0) {
new->next = *q;
*q = new;
return;
}
/* in between */
n_queue *cur = *q;
while (cur->next) {
if (cmp_notification(new->n, cur->next->n) > 0) {
new->next = cur->next;
cur->next = new;
return;
}
cur = cur->next;
}
/* last */
cur->next = new;
}
void n_queue_remove(n_queue **q, notification *n)
{
n_stack_remove(q, n);
}
notification *n_queue_dequeue(n_queue **q)
{
return n_stack_pop(q);
}
int n_queue_len(n_queue **q)
{
return n_stack_len(q);
}
str_array *str_array_malloc(void)
{
str_array *a = malloc(sizeof(str_array));
a->count = 0;
a->strs = NULL;
return a;
}
void str_array_append(str_array *a, char *str)
{
if (!a)
return;
a->count++;
a->strs = realloc(a->strs, a->count);
(a->strs)[a->count-1] = str;
}
void str_array_dup_append(str_array *a, const char *str)
{
if (!a)
return;
char *dup = strdup(str);
str_array_append(a, dup);
}
void str_array_deep_free(str_array *a)
{
if (!a)
return;
for (int i = 0; i < a->count; i++) {
free((a->strs)[i]);
}
free(a);
}
/* vim: set ts=8 sw=8 tw=0: */

84
container.h Normal file
View File

@ -0,0 +1,84 @@
#ifndef _LIST_H
#define _LIST_H
#include "dunst.h"
typedef struct _n_stack {
notification *n;
struct _n_stack *next;
} n_stack;
typedef n_stack n_queue;
typedef struct _str_array {
int count;
char **strs;
} str_array;
str_array *str_array_malloc(void);
void str_array_dup_append(str_array *a, const char *str);
void str_array_append(str_array *a, char *str);
void str_array_deep_free(str_array *a);
int cmp_notification(notification *a, notification *b);
/************
* stack
*/
/**
* push notification onto stack
* creates a new stack if *s == NULL
*/
void n_stack_push(n_stack **s, notification *n);
/**
* remove and return notification from stack
* sets *s to NULL if stack is empty
*/
notification *n_stack_pop(n_stack **s);
/**
* remove notification from stack
*/
void n_stack_remove(n_stack **q, notification *n);
/**
* return length of stack
*/
int n_stack_len(n_stack **s);
/***************
* queue
*/
/**
* enqueue notification into queue
* creates a new queue if *q == NULL
*/
void n_queue_enqueue(n_queue **q, notification *n);
/**
* dequeues the next element from the queue.
* returns NULL if queue is empty
*/
notification *n_queue_dequeue(n_queue **q);
/**
* remove notification from queue
*/
void n_queue_remove(n_queue **q, notification *n);
/**
* return length of queue
*/
int n_queue_len(n_queue **q);
#endif
/* vim: set ts=8 sw=8 tw=0: */

15
draw.c
View File

@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/X.h>
@ -45,7 +46,7 @@ DEALINGS IN THE SOFTWARE.
#define MIN(a, b) ((a) < (b) ? (a) : (b))
void
drawrect(DC * dc, int x, int y, unsigned int w, unsigned int h, Bool fill,
drawrect(DC * dc, int x, int y, unsigned int w, unsigned int h, bool fill,
unsigned long color)
{
XSetForeground(dc->dpy, dc->gc, color);
@ -71,7 +72,7 @@ void drawtext(DC * dc, const char *text, ColorSet * col)
if (mn < n)
for (n = MAX(mn - 3, 0); n < mn; buf[n++] = '.') ;
drawrect(dc, 0, 0, dc->w, dc->h, True, col->BG);
drawrect(dc, 0, 0, dc->w, dc->h, true, col->BG);
drawtextn(dc, buf, mn, col);
}
@ -234,12 +235,12 @@ void initfont(DC * dc, const char *fontstr)
return;
}
void
setopacity(DC *dc, Window win, unsigned long opacity)
void setopacity(DC * dc, Window win, unsigned long opacity)
{
Atom _NET_WM_WINDOW_OPACITY = XInternAtom(dc->dpy, "_NET_WM_WINDOW_OPACITY", False);
XChangeProperty(dc->dpy, win, _NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)&opacity, 1L);
Atom _NET_WM_WINDOW_OPACITY =
XInternAtom(dc->dpy, "_NET_WM_WINDOW_OPACITY", false);
XChangeProperty(dc->dpy, win, _NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&opacity, 1L);
}
void mapdc(DC * dc, Window win, unsigned int w, unsigned int h)

8
draw.h
View File

@ -33,11 +33,13 @@ DEALINGS IN THE SOFTWARE.
#ifndef DRAW_H
#define DRAW_H
#include <stdbool.h>
#include <X11/Xft/Xft.h>
typedef struct {
int x, y, w, h;
Bool invert;
bool invert;
Display *dpy;
GC gc;
Pixmap canvas;
@ -59,7 +61,7 @@ typedef struct {
unsigned long BG;
} ColorSet;
void drawrect(DC * dc, int x, int y, unsigned int w, unsigned int h, Bool fill,
void drawrect(DC * dc, int x, int y, unsigned int w, unsigned int h, bool fill,
unsigned long color);
void drawtext(DC * dc, const char *text, ColorSet * col);
void drawtextn(DC * dc, const char *text, size_t n, ColorSet * col);
@ -70,7 +72,7 @@ unsigned long getcolor(DC * dc, const char *colstr);
ColorSet *initcolor(DC * dc, const char *foreground, const char *background);
DC *initdc(void);
void initfont(DC * dc, const char *fontstr);
void setopacity(DC *dc, Window win, unsigned long opacity);
void setopacity(DC * dc, Window win, unsigned long opacity);
void mapdc(DC * dc, Window win, unsigned int w, unsigned int h);
void resizedc(DC * dc, unsigned int w, unsigned int h);
int textnw(DC * dc, const char *text, size_t len);

1364
dunst.c

File diff suppressed because it is too large Load Diff

34
dunst.h
View File

@ -2,6 +2,8 @@
#pragma once
#include <stdbool.h>
#include "draw.h"
#define LOW 0
@ -12,7 +14,6 @@
#define ColFG 1
#define ColBG 0
enum alignment { left, center, right };
enum separator_color { FOREGROUND, AUTO };
enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD };
@ -23,6 +24,7 @@ typedef struct _dimension_t {
unsigned int h;
unsigned int w;
int mask;
int negative_width;
} dimension_t;
typedef struct _screen_info {
@ -30,30 +32,26 @@ typedef struct _screen_info {
dimension_t dim;
} screen_info;
typedef struct _draw_txt {
char *txt;
int line_count;
} draw_txt;
typedef struct _notification {
char *appname;
char *summary;
char *body;
char *icon;
char *msg;
draw_txt draw_txt_buf;
const char *format;
char *dbus_client;
time_t start;
time_t timestamp;
int timeout;
int urgency;
int redisplayed; /* has been displayed before? */
bool redisplayed; /* has been displayed before? */
int id;
int dup_count;
ColorSet *colors;
char *color_strings[2];
int progress; /* percentage + 1, 0 to hide */
int line_count;
struct { int count; char **strs; } *urls;
} notification;
typedef struct _notification_buffer {
@ -83,9 +81,27 @@ typedef struct _keyboard_shortcut {
KeyCode code;
KeySym sym;
KeySym mask;
int is_valid;
bool is_valid;
} keyboard_shortcut;
typedef struct _r_line {
ColorSet *colors;
char *str;
bool continues;
} r_line;
typedef struct r_line_cache {
int count;
int size;
r_line *lines;
} r_line_cache;
typedef struct _rule_array {
int count;
rule_t *rules;
} rule_array;
extern int verbosity;
/* return id of notification */

View File

@ -3,7 +3,7 @@
#include <dbus/dbus.h>
#include "dunst.h"
#include "list.h"
#include "container.h"
#include "dunst_dbus.h"
@ -131,11 +131,8 @@ void dbus_poll(int timeout)
dbus_connection_read_write(dbus_conn, timeout);
dbus_msg = dbus_connection_pop_message(dbus_conn);
/* we don't have a new message */
if (dbus_msg == NULL) {
return;
}
while (dbus_msg) {
if (dbus_message_is_method_call
(dbus_msg, "org.freedesktop.DBus.Introspectable", "Introspect")) {
dbus_introspect(dbus_msg);
@ -162,6 +159,8 @@ void dbus_poll(int timeout)
closeNotification(dbus_msg);
}
dbus_message_unref(dbus_msg);
dbus_msg = dbus_connection_pop_message(dbus_conn);
}
}
void getCapabilities(DBusMessage * dmsg)
@ -336,11 +335,17 @@ void notify(DBusMessage * dmsg)
continue;
}
dbus_message_iter_get_basic(&hint, &hint_name);
_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);
_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);
@ -358,7 +363,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->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++) {
@ -366,7 +371,9 @@ void notify(DBusMessage * dmsg)
}
n->color_strings[ColFG] = fgcolor == NULL ? NULL : strdup(fgcolor);
n->color_strings[ColBG] = bgcolor == NULL ? NULL : strdup(bgcolor);
id = init_notification(n, replaces_id);
if (id > 0)
map_win();
reply = dbus_message_new_method_return(dmsg);

16
dunstrc
View File

@ -43,6 +43,8 @@
# the window expands to the longest message displayed.
# A positive x is measured from the left, a negative from the
# right side of the screen. Y is measured from the top and down respectevly.
# The width can be negative. In this case the actual width is the
# screen width minus the width defined in within the geometry option.
geometry = "0x3-30+20"
# The transparency of the window. range: [0; 100]
@ -87,6 +89,17 @@
# that fits nicely to the background color.
separator_color = auto
# print a notification on startup
# This is mainly for error detection, since dbus (re-)starts dunst
# automatically after a crash.
startup_notification = false
# dmenu path
dmenu = /usr/bin/dmenu -p dunst:
# browser for opening urls in context menu
browser = /usr/bin/firefox -new-tab
[shortcuts]
# shortcuts are specified as [modifier+][modifier+]...key
@ -104,6 +117,9 @@
# On the US keyboard layout 'grave' is normally above TAB and left of '1'.
history = ctrl+grave
# context menu
context = ctrl+shift+period
[urgency_low]
# IMPORTANT: colors have to be defined in quotation marks.
# Otherwise the '#' and following would be interpreted as a comment.

266
list.c
View File

@ -1,266 +0,0 @@
#include "stdlib.h"
#include "stdio.h"
#include "list.h"
int l_push(list * l, void *data)
{
l_node *n;
int ret;
/* invalid input */
if (!l || !data) {
return -1;
}
n = l_init_node(data);
if (!n) {
/* something went wrong */
return -2;
}
ret = l_node_push(l, n);
return ret;
}
int l_node_push(list * l, l_node * n)
{
l_node *end;
/* invalid input */
if (!l || !n) {
return -1;
}
n->next = NULL;
/* empty list */
if (!l->head) {
l->head = n;
return 0;
}
for (end = l->head; end->next; end = end->next) ;
if (end != n) {
end->next = n;
}
return 0;
}
void *l_pop(list * l)
{
l_node *penultimate;
void *data;
/* invalid input */
if (!l) {
return NULL;
}
/* empty list */
if (!l->head) {
return NULL;
}
/* len(l) == 1 */
if (!l->head->next) {
data = l->head->data;
free(l->head);
l->head = NULL;
return data;
}
for (penultimate = l->head;
penultimate->next->next; penultimate = penultimate->next) ;
data = penultimate->next->data;
free(penultimate->next);
penultimate->next = NULL;
return data;
}
int l_insert(l_node * node, void *data)
{
int ret;
l_node *to_be_inserted;
/* invalid input */
if (!node || !data) {
return -1;
}
to_be_inserted = l_init_node(data);
if (!to_be_inserted) {
return -2;
}
ret = l_node_insert(node, to_be_inserted);
return ret;
}
int l_node_insert(l_node * node, l_node * to_be_inserted)
{
l_node *tmp;
/* invalid input */
if (!node || !to_be_inserted) {
return -1;
}
tmp = node->next;
node->next = to_be_inserted;
to_be_inserted->next = tmp;
return 0;
}
void *l_remove(list * l, l_node * node)
{
void *data;
if (l != NULL) {
l_node_remove(l, node);
}
if (node == NULL) {
return NULL;
}
data = node->data;
free(node);
return data;
}
l_node *l_node_remove(list * l, l_node * node)
{
l_node *prev;
l_node *next;
/* invalid input */
if (!l || !node) {
return NULL;
}
/* empty list */
if (!l->head) {
return NULL;
}
/* node is head */
if (l->head == node) {
l->head = node->next;
node->next = NULL;
return node;
}
/* find the predecessor of node */
for (prev = l->head;
prev->next && prev->next != node; prev = prev->next) ;
/* node not in list */
if (prev->next != node) {
return node;
}
next = node->next;
prev->next = next;
return node;
}
l_node *l_init_node(void *data)
{
l_node *node;
node = malloc(sizeof(l_node));
if (!node) {
return NULL;
}
node->data = data;
node->next = NULL;
return node;
}
int l_length(list * l)
{
l_node *iter;
int count;
if (!l || !l->head) {
return 0;
}
count = 0;
iter = l->head;
while (iter) {
count++;
iter = iter->next;
}
return count;
}
int l_is_empty(list * l)
{
return l->head == NULL;
}
int l_move(list * from, list * to, l_node * node)
{
if (!from || !to || !node) {
return -1;
}
node = l_node_remove(from, node);
return l_node_push(to, node);
}
list *l_init(void)
{
list *l = malloc(sizeof(list));
l->head = NULL;
return l;
}
void l_sort(list * l, int (*f) (void *, void *))
{
list *old_list;
if (!l || l_length(l) < 2) {
/* nothing to do */
return;
}
old_list = l_init();
old_list->head = l->head;
l->head = NULL;
while (!l_is_empty(old_list)) {
l_node *iter;
l_node *max;
/* find max in old_list */
max = old_list->head;
for (iter = old_list->head; iter; iter = iter->next) {
if (f(max->data, iter->data) < 0) {
max = iter;
}
}
l_move(old_list, l, max);
}
free(old_list);
}
/* vim: set ts=8 sw=8 tw=0: */

59
list.h
View File

@ -1,59 +0,0 @@
#ifndef _LIST_H
#define _LIST_H
typedef struct _l_node {
struct _l_node *next;
void *data;
} l_node;
typedef struct _list {
l_node *head;
} list;
/* append to end of list */
int l_push(list * l, void *data);
/* same as append but with a l_node */
int l_node_push(list * l, l_node * n);
/* remove and return last element of list */
void *l_pop(list * l);
/* insert after node. */
int l_insert(l_node * node, void *data);
/*
* same as insert, but using a node_t
*/
int l_node_insert(l_node * node, l_node * to_be_inserted);
/*
* remove l_node from list and return a pointer to its data
*/
void *l_remove(list * l, l_node * node);
/*
* same as l_remove but returns the node instead of the data
*/
l_node *l_node_remove(list * l, l_node * node);
/*
* initialize a node
*/
l_node *l_init_node(void *data);
/* return the length of the list */
int l_length(list * l);
/* is list empty */
int l_is_empty(list * l);
/* move node from 'from' to 'to' */
int l_move(list * from, list * to, l_node * node);
void l_sort(list * l, int (*f) (void *, void *));
list *l_init(void);
#endif
/* vim: set ts=8 sw=8 tw=0: */

247
options.c
View File

@ -1,4 +1,6 @@
/* copyright 2012 Sascha Kruse and contributors (see LICENSE for licensing information) */
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
@ -19,11 +21,7 @@ typedef struct _section_t {
entry_t *entries;
} section_t;
static int section_count;
static int section_count = 0;
static section_t *sections;
static section_t *new_section(char *name);
@ -32,19 +30,27 @@ 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);
static int cmdline_argc;
static char **cmdline_argv;
static char *usage_str = NULL;
static void cmdline_usage_append(char *key, char *type, char *description);
static int cmdline_find_option(char *key);
section_t *new_section(char *name)
{
section_count++;
sections = realloc(sections, sizeof(section_t) *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 &sections[section_count -1];
return &sections[section_count - 1];
}
void free_ini(void)
{
for(int i = 0; i < section_count; i++) {
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);
@ -97,10 +103,13 @@ char *get_value(char *section, char *key)
char *ini_get_string(char *section, char *key, const char *def)
{
char *value = get_value(section, key);
if (value == NULL)
return def;
else
if (value)
return strdup(value);
if (def == NULL)
return NULL;
else
return strdup(def);
}
int ini_get_int(char *section, char *key, int def)
@ -112,7 +121,7 @@ int ini_get_int(char *section, char *key, int def)
return atoi(value);
}
double ini_get_double(char *section, char *key, int def)
double ini_get_double(char *section, char *key, double def)
{
char *value = get_value(section, key);
if (value == NULL)
@ -135,7 +144,7 @@ char *next_section(char *section)
if (i + 1 >= section_count)
return NULL;
else
return sections[i+1].name;
return sections[i + 1].name;
}
}
return NULL;
@ -182,7 +191,7 @@ char *clean_value(char *value)
}
int load_ini_file(FILE *fp)
int load_ini_file(FILE * fp)
{
char line[BUFSIZ];
@ -199,7 +208,9 @@ int load_ini_file(FILE *fp)
if (*start == '[') {
char *end = strstr(start + 1, "]");
if (!end) {
printf("Warning: invalid config file at line %d\n", line_num);
printf
("Warning: invalid config file at line %d\n",
line_num);
printf("Missing ']'\n");
continue;
}
@ -208,27 +219,30 @@ int load_ini_file(FILE *fp)
if (current_section)
free(current_section);
current_section = (strdup(start+1));
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("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 *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
("Warning: invalid config file at line %d\n",
line_num);
printf("Missing '\"'\n");
continue;
}
@ -244,7 +258,8 @@ int load_ini_file(FILE *fp)
value = rstrip(value);
if (!current_section) {
printf("Warning: invalid config file at line: %d\n", line_num);
printf("Warning: invalid config file at line: %d\n",
line_num);
printf("Key value pair without a section\n");
continue;
}
@ -255,4 +270,196 @@ int load_ini_file(FILE *fp)
free(current_section);
return 0;
}
void cmdline_load(int argc, char *argv[])
{
cmdline_argc = argc;
cmdline_argv = argv;
}
int cmdline_find_option(char *key)
{
if (!key) {
return -1;
}
char *key1 = strdup(key);
char *key2 = strstr(key1, "/");
if (key2) {
*key2 = '\0';
key2++;
}
/* look for first key */
for (int i = 0; i < cmdline_argc; i++) {
if (strcmp(key1, cmdline_argv[i]) == 0) {
free(key1);
return i;
}
}
/* look for second key if one was specified */
if (key2) {
for (int i = 0; i < cmdline_argc; i++) {
if (strcmp(key2, cmdline_argv[i]) == 0) {
free(key1);
return i;
}
}
}
free(key1);
return -1;
}
static char *cmdline_get_value(char *key)
{
int idx = cmdline_find_option(key);
if (idx < 0) {
return NULL;
}
if (idx + 1 >= cmdline_argc || cmdline_argv[idx + 1][0] == '-') {
/* the argument is missing */
fprintf(stderr, "Warning: %s, missing argument. Ignoring\n",
key);
return NULL;
}
return cmdline_argv[idx + 1];
}
char *cmdline_get_string(char *key, const char *def, char *description)
{
cmdline_usage_append(key, "string", description);
char *str = cmdline_get_value(key);
if (str)
return strdup(str);
if (def == NULL)
return NULL;
else
return strdup(def);
}
int cmdline_get_int(char *key, int def, char *description)
{
cmdline_usage_append(key, "double", description);
char *str = cmdline_get_value(key);
if (str == NULL)
return def;
else
return atoi(str);
}
double cmdline_get_double(char *key, double def, char *description)
{
cmdline_usage_append(key, "double", description);
char *str = cmdline_get_value(key);
if (str == NULL)
return def;
else
return atof(str);
}
int cmdline_get_bool(char *key, int def, char *description)
{
cmdline_usage_append(key, "", description);
int idx = cmdline_find_option(key);
if (idx > 0)
return true;
else
return def;
}
char *option_get_string(char *ini_section, char *ini_key, char *cmdline_key,
const char *def, char *description)
{
char *val = NULL;
if (cmdline_key) {
val = cmdline_get_string(cmdline_key, NULL, description);
}
if (val) {
return val;
} else {
return ini_get_string(ini_section, ini_key, def);
}
}
int option_get_int(char *ini_section, char *ini_key, char *cmdline_key, int def,
char *description)
{
/* *str is only used to check wether the cmdline option is actually set. */
char *str = cmdline_get_value(cmdline_key);
/* we call cmdline_get_int even when the option isn't set in order to
* add the usage info */
int val = cmdline_get_int(cmdline_key, def, description);
if (!str)
return ini_get_int(ini_section, ini_key, def);
else
return val;
}
double option_get_double(char *ini_section, char *ini_key, char *cmdline_key,
double def, char *description)
{
char *str = cmdline_get_value(cmdline_key);
double val = cmdline_get_double(cmdline_key, def, description);
if (!str)
return ini_get_int(ini_section, ini_key, def);
else
return val;
}
int option_get_bool(char *ini_section, char *ini_key, char *cmdline_key,
int def, char *description)
{
int val = false;
if (cmdline_key)
val = cmdline_get_bool(cmdline_key, false, description);
if (cmdline_key && val) {
/* this can only be true if the value has been set,
* so we can return */
return true;
}
return ini_get_bool(ini_section, ini_key, def);
}
void cmdline_usage_append(char *key, char *type, char *description)
{
char *key_type;
if (type && strlen(type) > 0)
asprintf(&key_type, "%s (%s)", key, type);
else
asprintf(&key_type, "%s", key);
if (!usage_str) {
asprintf(&usage_str, "%-40s - %s\n", key_type, description);
free(key_type);
return;
}
char *tmp;
asprintf(&tmp, "%s%-40s - %s\n", usage_str, key_type, description);
free(key_type);
free(usage_str);
usage_str = tmp;
}
char *cmdline_create_usage(void)
{
return strdup(usage_str);
}
/* vim: set ts=8 sw=8 tw=0: */

View File

@ -3,14 +3,30 @@
#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);
double ini_get_double(char *section, char *key, double def);
int ini_get_bool(char *section, char *key, int def);
void free_ini(void);
void cmdline_load(int argc, char *argv[]);
/* for all cmdline_get_* key can be either "-key" or "-key/-longkey" */
char *cmdline_get_string(char *key, const char *def, char *description);
int cmdline_get_int(char *key, int def, char *description);
double cmdline_get_double(char *key, double def, char *description);
int cmdline_get_bool(char *key, int def, char *description);
char *cmdline_create_usage(void);
char *option_get_string(char *ini_section, char *ini_key, char *cmdline_key,
const char *def, char *description);
int option_get_int(char *ini_section, char *ini_key, char *cmdline_key, int def,
char *description);
double option_get_double(char *ini_section, char *ini_key, char *cmdline_key,
double def, char *description);
int option_get_bool(char *ini_section, char *ini_key, char *cmdline_key,
int def, char *description);
/* returns the next known section.
* if section == NULL returns first section.
* returns NULL if no more sections are available

43
utils.c
View File

@ -1,3 +1,5 @@
#define _GNU_SOURCE
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
@ -6,7 +8,6 @@
#include "utils.h"
#include "dunst.h"
char *rstrip(char *str)
{
char *end;
@ -20,7 +21,7 @@ char *rstrip(char *str)
char *lskip(char *s)
{
for(; *s && isspace(*s); s++);
for (; *s && isspace(*s); s++) ;
return s;
}
@ -44,17 +45,47 @@ char *string_replace(const char *needle, const char *replacement,
sprintf(tmp + strlen(tmp), "%s%s", replacement, start + strlen(needle));
free(haystack);
if (strstr(tmp, needle)) {
return string_replace(needle, replacement, tmp);
} else {
return tmp;
}
char *string_append(char *a, const char *b, const char *sep)
{
if (!a)
return strdup(b);
char *new;
if (!sep)
asprintf(&new, "%s%s", a, b);
else
asprintf(&new, "%s%s%s", a, sep, b);
free(a);
return new;
}
char **string_to_argv(const char *s)
{
char *str = strdup(s);
char **argv = NULL;
char *p = strtok (str, " ");
int n_spaces = 0;
while (p) {
argv = realloc (argv, sizeof (char*) * ++n_spaces);
argv[n_spaces-1] = p;
p = strtok (NULL, " ");
}
argv = realloc (argv, sizeof (char*) * (n_spaces+1));
argv[n_spaces] = NULL;
return argv;
}
int digit_count(int i)
{
int len = 0;
if ( i == 0) {
if (i == 0) {
return 1;
}

View File

@ -8,8 +8,12 @@ char *lskip(char *str);
char *string_replace(const char *needle, const char *replacement,
char *haystack);
char *string_append(char *a, const char *b, const char *sep);
char **string_to_argv(const char *s);
/* exit with an error message */
void die(char * msg, int exit_value);
void die(char *msg, int exit_value);
int digit_count(int i);