Merge branch 'next'
This commit is contained in:
commit
67774c3e46
11
Makefile
11
Makefile
@ -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
|
||||
|
15
README.pod
15
README.pod
@ -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).
|
||||
|
14
config.def.h
14
config.def.h
@ -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
177
container.c
Normal 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
84
container.h
Normal 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
15
draw.c
@ -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
8
draw.h
@ -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);
|
||||
|
34
dunst.h
34
dunst.h
@ -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 */
|
||||
|
29
dunst_dbus.c
29
dunst_dbus.c
@ -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
16
dunstrc
@ -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
266
list.c
@ -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
59
list.h
@ -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
247
options.c
@ -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 §ions[section_count -1];
|
||||
return §ions[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: */
|
||||
|
20
options.h
20
options.h
@ -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
43
utils.c
@ -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;
|
||||
}
|
||||
|
||||
|
6
utils.h
6
utils.h
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user