From 4b84287d1935144625bd506facbf56e8470ce5be Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 14:39:44 +0000 Subject: [PATCH 01/20] tab completion support for menus; from Alexander Polakov. ok sthen@ on an older incarnation --- calmwm.h | 10 +++++++- kbfunc.c | 9 ++++--- menu.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- search.c | 48 +++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 8 deletions(-) diff --git a/calmwm.h b/calmwm.h index 5d96485..e08269b 100644 --- a/calmwm.h +++ b/calmwm.h @@ -73,6 +73,10 @@ #define CWM_RCYCLE 0x0002 #define CWM_INGROUP 0x0004 +/* menu */ +#define CWM_MENU_DUMMY 0x0001 +#define CWM_MENU_FILE 0x0002 + #define KBTOGROUP(X) ((X) - 1) union arg { @@ -260,7 +264,7 @@ TAILQ_HEAD(cmd_q, cmd); struct menu { TAILQ_ENTRY(menu) entry; TAILQ_ENTRY(menu) resultentry; -#define MENU_MAXENTRY 50 +#define MENU_MAXENTRY 200 char text[MENU_MAXENTRY + 1]; char print[MENU_MAXENTRY + 1]; void *ctx; @@ -355,6 +359,10 @@ void search_match_client(struct menu_q *, struct menu_q *, char *); void search_match_exec(struct menu_q *, struct menu_q *, char *); +void search_match_exec_path(struct menu_q *, struct menu_q *, + char *); +void search_match_path_any(struct menu_q *, struct menu_q *, + char *); void search_match_text(struct menu_q *, struct menu_q *, char *); void search_print_client(struct menu *, int); diff --git a/kbfunc.c b/kbfunc.c index e11a3cb..1920c5d 100644 --- a/kbfunc.c +++ b/kbfunc.c @@ -298,8 +298,9 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg) } xfree(path); - if ((mi = menu_filter(sc, &menuq, label, NULL, 1, - search_match_exec, NULL)) != NULL) { + if ((mi = menu_filter(sc, &menuq, label, NULL, + CWM_MENU_DUMMY | CWM_MENU_FILE, + search_match_exec_path, NULL)) != NULL) { if (mi->text[0] == '\0') goto out; switch (cmd) { @@ -376,7 +377,7 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg) xfree(lbuf); (void)fclose(fp); - if ((mi = menu_filter(sc, &menuq, "ssh", NULL, 1, + if ((mi = menu_filter(sc, &menuq, "ssh", NULL, CWM_MENU_DUMMY, search_match_exec, NULL)) != NULL) { if (mi->text[0] == '\0') goto out; @@ -403,7 +404,7 @@ kbfunc_client_label(struct client_ctx *cc, union arg *arg) TAILQ_INIT(&menuq); /* dummy is set, so this will always return */ - mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1, + mi = menu_filter(cc->sc, &menuq, "label", cc->label, CWM_MENU_DUMMY, search_match_text, NULL); if (!mi->abort) { diff --git a/menu.c b/menu.c index 4a532a9..e32994b 100644 --- a/menu.c +++ b/menu.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "calmwm.h" @@ -37,10 +38,11 @@ enum ctltype { CTL_NONE = -1, CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN, - CTL_ABORT, CTL_ALL + CTL_TAB, CTL_ABORT, CTL_ALL }; struct menu_ctx { + struct screen_ctx *sc; char searchstr[MENU_MAXENTRY + 1]; char dispstr[MENU_MAXENTRY*2 + 1]; char promptstr[MENU_MAXENTRY + 1]; @@ -54,6 +56,7 @@ struct menu_ctx { int height; int width; int num; + int flags; int x; int y; void (*match)(struct menu_q *, struct menu_q *, char *); @@ -93,7 +96,7 @@ menu_init(struct screen_ctx *sc) struct menu * menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, - char *initial, int dummy, + char *initial, int flags, void (*match)(struct menu_q *, struct menu_q *, char *), void (*print)(struct menu *, int)) { @@ -114,6 +117,8 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, xsave = mc.x; ysave = mc.y; + mc.sc = sc; + mc.flags = flags; if (prompt == NULL) { evmask = MENUMASK; mc.promptstr[0] = '\0'; @@ -181,7 +186,8 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, } } out: - if (dummy == 0 && mi->dummy) { /* no mouse based match */ + if ((mc.flags & CWM_MENU_DUMMY) == 0 && mi->dummy) { + /* no mouse based match */ xfree(mi); mi = NULL; } @@ -199,6 +205,38 @@ out: return (mi); } +static struct menu * +menu_complete_path(struct menu_ctx *mc) +{ + struct menu *mi, *mr; + struct menu_q menuq; + char *path = NULL; + + path = xcalloc(1, sizeof(mr->text)); + mr = xcalloc(1, sizeof(*mr)); + + TAILQ_INIT(&menuq); + if ((mi = menu_filter(mc->sc, &menuq, mc->searchstr, NULL, + CWM_MENU_DUMMY, search_match_path_any, NULL)) != NULL) { + mr->abort = mi->abort; + mr->dummy = mi->dummy; + strlcpy(path, mi->text, sizeof(mi->text)); + } + + while ((mi = TAILQ_FIRST(&menuq)) != NULL) { + TAILQ_REMOVE(&menuq, mi, entry); + xfree(mi); + } + + if (path[0] != '\0') + snprintf(mr->text, sizeof(mr->text), "%s \"%s\"", + mc->searchstr, path); + else if (!mr->abort) + strlcpy(mr->text, mc->searchstr, sizeof(mr->text)); + xfree(path); + return (mr); +} + static struct menu * menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq) @@ -257,6 +295,35 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq, mc->searchstr[0] = '\0'; mc->changed = 1; break; + case CTL_TAB: + if ((mi = TAILQ_FIRST(resultq)) != NULL) { + /* + * - We are in exec_path menu mode + * - There's only one result + * - It is equal to the input + * We got a command, launch the file menu + */ + if ((mc->flags & CWM_MENU_FILE) && + (TAILQ_NEXT(mi, resultentry) == NULL) && + (strncmp(mc->searchstr, mi->text, + strlen(mi->text))) == 0) + return (menu_complete_path(mc)); + + /* + * Put common prefix of the results into searchstr + */ + (void)strlcpy(mc->searchstr, + mi->text, sizeof(mc->searchstr)); + while ((mi = TAILQ_NEXT(mi, resultentry)) != NULL) { + i = 0; + while (tolower(mc->searchstr[i]) == + tolower(mi->text[i])) + i++; + mc->searchstr[i] = '\0'; + } + mc->changed = 1; + } + break; case CTL_ALL: mc->list = !mc->list; break; @@ -484,6 +551,9 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr) case XK_Return: *ctl = CTL_RETURN; break; + case XK_Tab: + *ctl = CTL_TAB; + break; case XK_Up: *ctl = CTL_UP; break; diff --git a/search.c b/search.c index 8d58067..e19c9c8 100644 --- a/search.c +++ b/search.c @@ -29,9 +29,12 @@ #include #include #include +#include #include "calmwm.h" +#define PATH_EXEC 0x1 + static int strsubmatch(char *, char *, int); /* @@ -161,6 +164,43 @@ search_print_client(struct menu *mi, int list) } } +static void +search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search, int flag) +{ + struct menu *mi; + char pattern[MAXPATHLEN]; + glob_t g; + int i; + + TAILQ_INIT(resultq); + + (void)strlcpy(pattern, search, sizeof(pattern)); + (void)strlcat(pattern, "*", sizeof(pattern)); + + if (glob(pattern, GLOB_MARK, NULL, &g) != 0) + return; + for (i = 0; i < g.gl_pathc; i++) { + if ((flag & PATH_EXEC) && access(g.gl_pathv[i], X_OK)) + continue; + mi = xcalloc(1, sizeof(*mi)); + (void)strlcpy(mi->text, g.gl_pathv[i], sizeof(mi->text)); + TAILQ_INSERT_TAIL(resultq, mi, resultentry); + } + globfree(&g); +} + +void +search_match_path_exec(struct menu_q *menuq, struct menu_q *resultq, char *search) +{ + return (search_match_path(menuq, resultq, search, PATH_EXEC)); +} + +void +search_match_path_any(struct menu_q *menuq, struct menu_q *resultq, char *search) +{ + return (search_match_path(menuq, resultq, search, 0)); +} + void search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search) { @@ -196,6 +236,14 @@ search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search) } } +void +search_match_exec_path(struct menu_q *menuq, struct menu_q *resultq, char *search) +{ + search_match_exec(menuq, resultq, search); + if (TAILQ_EMPTY(resultq)) + search_match_path_exec(menuq, resultq, search); +} + static int strsubmatch(char *sub, char *str, int zeroidx) { From c53c1af2db17dd4b9fb2d1fbc1b909e32b060531 Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 14:40:51 +0000 Subject: [PATCH 02/20] spacing --- calmwm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/calmwm.h b/calmwm.h index e08269b..9b2a4ca 100644 --- a/calmwm.h +++ b/calmwm.h @@ -74,8 +74,8 @@ #define CWM_INGROUP 0x0004 /* menu */ -#define CWM_MENU_DUMMY 0x0001 -#define CWM_MENU_FILE 0x0002 +#define CWM_MENU_DUMMY 0x0001 +#define CWM_MENU_FILE 0x0002 #define KBTOGROUP(X) ((X) - 1) From 438c0332a11ee13494d4bcebdb28607efbdd2f65 Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 14:49:46 +0000 Subject: [PATCH 03/20] missing headers; from Thordur Bjornsson. --- kbfunc.c | 1 + xevents.c | 1 + 2 files changed, 2 insertions(+) diff --git a/kbfunc.c b/kbfunc.c index 1920c5d..b6c0a0d 100644 --- a/kbfunc.c +++ b/kbfunc.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/xevents.c b/xevents.c index eddf4fe..0d91067 100644 --- a/xevents.c +++ b/xevents.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include From 94db8ca2ed43a8e89c6c7f1ad652ea8127820131 Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 14:58:26 +0000 Subject: [PATCH 04/20] zap trailing space --- cwmrc.5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cwmrc.5 b/cwmrc.5 index ffc4d0c..7bf26a0 100644 --- a/cwmrc.5 +++ b/cwmrc.5 @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 31 2012 $ +.Dd $Mdocdate: November 1 2012 $ .Dt CWMRC 5 .Os .Sh NAME @@ -58,7 +58,7 @@ is 0, matching windows will not be added to any group; this may be used to override .Dq sticky group mode . .Pp -The name and class values, respectively, for existing windows +The name and class values, respectively, for existing windows may be obtained using .Xr xprop 1 . .Pp From dfb6aed82aa9a75d895f75984013f07a474c4d7a Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 14:59:07 +0000 Subject: [PATCH 05/20] clarify windowname and windowclass values are pulled from the WM_CLASS property; from Kent Spillner --- cwmrc.5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cwmrc.5 b/cwmrc.5 index 7bf26a0..39ab221 100644 --- a/cwmrc.5 +++ b/cwmrc.5 @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: November 1 2012 $ +.Dd $Mdocdate: November 7 2012 $ .Dt CWMRC 5 .Os .Sh NAME @@ -59,7 +59,7 @@ used to override .Dq sticky group mode . .Pp The name and class values, respectively, for existing windows -may be obtained using +are both set in the WM_CLASS property and may be obtained using .Xr xprop 1 . .Pp .It Ic bind Ar keys command From 76b0874b4caa937b5313b3604208d050b4868b04 Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 20:34:39 +0000 Subject: [PATCH 06/20] get rid of the xfree() wrapper around free(); from Tiago Cunha. --- calmwm.h | 1 - client.c | 10 +++++----- conf.c | 25 ++++++++++++------------- group.c | 6 +++--- kbfunc.c | 21 ++++++++++----------- menu.c | 6 +++--- mousefunc.c | 4 ++-- xmalloc.c | 6 ------ xutil.c | 2 +- 9 files changed, 36 insertions(+), 45 deletions(-) diff --git a/calmwm.h b/calmwm.h index 9b2a4ca..4bc97f4 100644 --- a/calmwm.h +++ b/calmwm.h @@ -490,7 +490,6 @@ void u_exec(char *); void u_spawn(char *); void *xcalloc(size_t, size_t); -void xfree(void *); void *xmalloc(size_t); char *xstrdup(const char *); diff --git a/client.c b/client.c index 8cb119f..c2da98c 100644 --- a/client.c +++ b/client.c @@ -166,12 +166,12 @@ client_delete(struct client_ctx *cc) while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) { TAILQ_REMOVE(&cc->nameq, wn, entry); if (wn->name != emptystring) - xfree(wn->name); - xfree(wn); + free(wn->name); + free(wn); } client_freehints(cc); - xfree(cc); + free(cc); } void @@ -582,8 +582,8 @@ match: assert(wn != NULL); TAILQ_REMOVE(&cc->nameq, wn, entry); if (wn->name != emptystring) - xfree(wn->name); - xfree(wn); + free(wn->name); + free(wn); cc->nameqlen--; } } diff --git a/conf.c b/conf.c index 57e45a2..9e40fa2 100644 --- a/conf.c +++ b/conf.c @@ -202,36 +202,35 @@ conf_clear(struct conf *c) while ((cmd = TAILQ_FIRST(&c->cmdq)) != NULL) { TAILQ_REMOVE(&c->cmdq, cmd, entry); - xfree(cmd); + free(cmd); } while ((kb = TAILQ_FIRST(&c->keybindingq)) != NULL) { TAILQ_REMOVE(&c->keybindingq, kb, entry); - xfree(kb); + free(kb); } while ((ag = TAILQ_FIRST(&c->autogroupq)) != NULL) { TAILQ_REMOVE(&c->autogroupq, ag, entry); - xfree(ag->class); - if (ag->name) - xfree(ag->name); - xfree(ag); + free(ag->class); + free(ag->name); + free(ag); } while ((wm = TAILQ_FIRST(&c->ignoreq)) != NULL) { TAILQ_REMOVE(&c->ignoreq, wm, entry); - xfree(wm); + free(wm); } while ((mb = TAILQ_FIRST(&c->mousebindingq)) != NULL) { TAILQ_REMOVE(&c->mousebindingq, mb, entry); - xfree(mb); + free(mb); } for (i = 0; i < CWM_COLOR_MAX; i++) - xfree(c->color[i].name); + free(c->color[i].name); - xfree(c->font); + free(c->font); } void @@ -477,7 +476,7 @@ conf_bindname(struct conf *c, char *name, char *binding) if (current_binding->keysym == NoSymbol && current_binding->keycode == 0) { - xfree(current_binding); + free(current_binding); return; } @@ -523,7 +522,7 @@ conf_unbind(struct conf *c, struct keybinding *unbind) key->keysym == unbind->keysym) { conf_ungrab(c, key); TAILQ_REMOVE(&c->keybindingq, key, entry); - xfree(key); + free(key); } } } @@ -603,7 +602,7 @@ conf_mouseunbind(struct conf *c, struct mousebinding *unbind) if (mb->button == unbind->button) { TAILQ_REMOVE(&c->mousebindingq, mb, entry); - xfree(mb); + free(mb); } } } diff --git a/group.c b/group.c index 3370643..dd748ea 100644 --- a/group.c +++ b/group.c @@ -129,7 +129,7 @@ group_show(struct screen_ctx *sc, struct group_ctx *gc) } XRestackWindows(X_Dpy, winlist, gc->nhidden); - xfree(winlist); + free(winlist); gc->hidden = 0; group_setactive(sc, gc->shortcut - 1); @@ -387,7 +387,7 @@ group_menu(XButtonEvent *e) cleanup: while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } } @@ -491,7 +491,7 @@ group_update_names(struct screen_ctx *sc) if (prop_ret != NULL) XFree(prop_ret); if (sc->group_nonames != 0) - xfree(sc->group_names); + free(sc->group_names); sc->group_names = strings; sc->group_nonames = n; diff --git a/kbfunc.c b/kbfunc.c index b6c0a0d..c67222e 100644 --- a/kbfunc.c +++ b/kbfunc.c @@ -170,7 +170,7 @@ kbfunc_client_search(struct client_ctx *cc, union arg *arg) while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } } @@ -197,7 +197,7 @@ kbfunc_menu_search(struct client_ctx *cc, union arg *arg) while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } } @@ -297,7 +297,7 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg) } (void)closedir(dirp); } - xfree(path); + free(path); if ((mi = menu_filter(sc, &menuq, label, NULL, CWM_MENU_DUMMY | CWM_MENU_FILE, @@ -319,10 +319,10 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg) } out: if (mi != NULL && mi->dummy) - xfree(mi); + free(mi); while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } } @@ -375,7 +375,7 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg) (void)strlcpy(mi->text, hostbuf, sizeof(mi->text)); TAILQ_INSERT_TAIL(&menuq, mi, entry); } - xfree(lbuf); + free(lbuf); (void)fclose(fp); if ((mi = menu_filter(sc, &menuq, "ssh", NULL, CWM_MENU_DUMMY, @@ -389,10 +389,10 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg) } out: if (mi != NULL && mi->dummy) - xfree(mi); + free(mi); while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } } @@ -409,11 +409,10 @@ kbfunc_client_label(struct client_ctx *cc, union arg *arg) search_match_text, NULL); if (!mi->abort) { - if (cc->label != NULL) - xfree(cc->label); + free(cc->label); cc->label = xstrdup(mi->text); } - xfree(mi); + free(mi); } void diff --git a/menu.c b/menu.c index e32994b..0fff91e 100644 --- a/menu.c +++ b/menu.c @@ -188,7 +188,7 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, out: if ((mc.flags & CWM_MENU_DUMMY) == 0 && mi->dummy) { /* no mouse based match */ - xfree(mi); + free(mi); mi = NULL; } @@ -225,7 +225,7 @@ menu_complete_path(struct menu_ctx *mc) while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } if (path[0] != '\0') @@ -233,7 +233,7 @@ menu_complete_path(struct menu_ctx *mc) mc->searchstr, path); else if (!mr->abort) strlcpy(mr->text, mc->searchstr, sizeof(mr->text)); - xfree(path); + free(path); return (mr); } diff --git a/mousefunc.c b/mousefunc.c index c615052..3521d71 100644 --- a/mousefunc.c +++ b/mousefunc.c @@ -253,7 +253,7 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg) } else { while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } } } @@ -282,6 +282,6 @@ mousefunc_menu_cmd(struct client_ctx *cc, void *arg) else while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } } diff --git a/xmalloc.c b/xmalloc.c index 7860b97..27114d1 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -52,12 +52,6 @@ xcalloc(size_t no, size_t siz) return (p); } -void -xfree(void *p) -{ - free(p); -} - char * xstrdup(const char *str) { diff --git a/xutil.c b/xutil.c index 5dbc911..bcde1c5 100644 --- a/xutil.c +++ b/xutil.c @@ -339,7 +339,7 @@ xu_ewmh_net_client_list(struct screen_ctx *sc) winlist[j++] = cc->win; XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST].atom, XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i); - xfree(winlist); + free(winlist); } void From bd252183338229977adc77849a857b597908f71c Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 20:37:55 +0000 Subject: [PATCH 07/20] plug a leak when using 'unmap' for kbd/mouse bindings; from Tiago Cunha. --- conf.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/conf.c b/conf.c index 9e40fa2..df3566a 100644 --- a/conf.c +++ b/conf.c @@ -483,8 +483,10 @@ conf_bindname(struct conf *c, char *name, char *binding) /* We now have the correct binding, remove duplicates. */ conf_unbind(c, current_binding); - if (strcmp("unmap", binding) == 0) + if (strcmp("unmap", binding) == 0) { + free(current_binding); return; + } for (iter = 0; iter < nitems(name_to_kbfunc); iter++) { if (strcmp(name_to_kbfunc[iter].tag, binding) != 0) @@ -574,8 +576,10 @@ conf_mousebind(struct conf *c, char *name, char *binding) conf_mouseunbind(c, current_binding); - if (strcmp("unmap", binding) == 0) + if (strcmp("unmap", binding) == 0) { + free(current_binding); return; + } for (iter = 0; iter < nitems(name_to_mousefunc); iter++) { if (strcmp(name_to_mousefunc[iter].tag, binding) != 0) From 7f1851b8f60ad4aead8668e8ea37e8e85d315383 Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 21:01:48 +0000 Subject: [PATCH 08/20] now that we have FOREACH_SAFE queue macros, use them where appropriate; from Tiago Cunha. --- conf.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/conf.c b/conf.c index df3566a..1e8415f 100644 --- a/conf.c +++ b/conf.c @@ -512,10 +512,7 @@ conf_unbind(struct conf *c, struct keybinding *unbind) { struct keybinding *key = NULL, *keynxt; - for (key = TAILQ_FIRST(&c->keybindingq); - key != TAILQ_END(&c->keybindingq); key = keynxt) { - keynxt = TAILQ_NEXT(key, entry); - + TAILQ_FOREACH_SAFE(key, &c->keybindingq, entry, keynxt) { if (key->modmask != unbind->modmask) continue; @@ -597,10 +594,7 @@ conf_mouseunbind(struct conf *c, struct mousebinding *unbind) { struct mousebinding *mb = NULL, *mbnxt; - for (mb = TAILQ_FIRST(&c->mousebindingq); - mb != TAILQ_END(&c->mousebindingq); mb = mbnxt) { - mbnxt = TAILQ_NEXT(mb, entry); - + TAILQ_FOREACH_SAFE(mb, &c->mousebindingq, entry, mbnxt) { if (mb->modmask != unbind->modmask) continue; From 55edbe460da2a91aa80555e1b2af417307fc5004 Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 21:04:55 +0000 Subject: [PATCH 09/20] add comment why we mouse unbind, just like kbd --- conf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/conf.c b/conf.c index 1e8415f..bf063d5 100644 --- a/conf.c +++ b/conf.c @@ -571,6 +571,7 @@ conf_mousebind(struct conf *c, char *name, char *binding) if (errstr) warnx("number of buttons is %s: %s", errstr, substring); + /* We now have the correct binding, remove duplicates. */ conf_mouseunbind(c, current_binding); if (strcmp("unmap", binding) == 0) { From c9c0a5fdbb8ce451b9706fc33999a1667b60cd6f Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 7 Nov 2012 21:10:32 +0000 Subject: [PATCH 10/20] style nit; from Tiago Cunha. --- conf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/conf.c b/conf.c index bf063d5..7e1f3e2 100644 --- a/conf.c +++ b/conf.c @@ -461,9 +461,8 @@ conf_bindname(struct conf *c, char *name, char *binding) /* skip past the modifiers */ substring++; - } else { + } else substring = name; - } if (substring[0] == '[' && substring[strlen(substring)-1] == ']') { From 04d4ed7b7e1f71d72e326429dc816988892be7eb Mon Sep 17 00:00:00 2001 From: okan Date: Thu, 8 Nov 2012 20:18:19 +0000 Subject: [PATCH 11/20] fix some warnings; inspired by a diff from Thordur Bjornsson. --- calmwm.h | 2 +- group.c | 4 ++-- xutil.c | 9 +++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/calmwm.h b/calmwm.h index 4bc97f4..8c06db4 100644 --- a/calmwm.h +++ b/calmwm.h @@ -481,7 +481,7 @@ void xu_ewmh_net_wm_number_of_desktops(struct screen_ctx *); void xu_ewmh_net_showing_desktop(struct screen_ctx *); void xu_ewmh_net_virtual_roots(struct screen_ctx *); void xu_ewmh_net_current_desktop(struct screen_ctx *, long); -void xu_ewmh_net_desktop_names(struct screen_ctx *, unsigned char *, int); +void xu_ewmh_net_desktop_names(struct screen_ctx *, char *, int); void xu_ewmh_net_wm_desktop(struct client_ctx *); diff --git a/group.c b/group.c index dd748ea..cf431c6 100644 --- a/group.c +++ b/group.c @@ -472,7 +472,7 @@ group_update_names(struct screen_ctx *sc) strings = xmalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS : nstrings) * sizeof(*strings)); - p = prop_ret; + p = (char *)prop_ret; while (n < nstrings) { strings[n++] = xstrdup(p); p += strlen(p) + 1; @@ -502,7 +502,7 @@ group_update_names(struct screen_ctx *sc) static void group_set_names(struct screen_ctx *sc) { - unsigned char *p, *q; + char *p, *q; size_t len = 0, tlen, slen; int i; diff --git a/xutil.c b/xutil.c index bcde1c5..110ce87 100644 --- a/xutil.c +++ b/xutil.c @@ -188,7 +188,7 @@ xu_getstrprop(Window win, Atom atm, char **text) { XTextProperty prop2; if (Xutf8TextListToTextProperty(X_Dpy, list, nitems, XUTF8StringStyle, &prop2) == Success) { - *text = xstrdup(prop2.value); + *text = xstrdup((const char *)prop2.value); XFree(prop2.value); } } else { @@ -292,7 +292,8 @@ xu_ewmh_net_supported_wm_check(struct screen_ctx *sc) XChangeProperty(X_Dpy, w, ewmh[_NET_SUPPORTING_WM_CHECK].atom, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1); XChangeProperty(X_Dpy, w, ewmh[_NET_WM_NAME].atom, - XA_WM_NAME, 8, PropModeReplace, WMNAME, strlen(WMNAME)); + XA_WM_NAME, 8, PropModeReplace, (unsigned char *)WMNAME, + strlen(WMNAME)); } void @@ -396,10 +397,10 @@ xu_ewmh_net_current_desktop(struct screen_ctx *sc, long idx) } void -xu_ewmh_net_desktop_names(struct screen_ctx *sc, unsigned char *data, int n) +xu_ewmh_net_desktop_names(struct screen_ctx *sc, char *data, int n) { XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_NAMES].atom, - cwmh[UTF8_STRING].atom, 8, PropModeReplace, data, n); + cwmh[UTF8_STRING].atom, 8, PropModeReplace, (unsigned char *)data, n); } /* Application Window Properties */ From 28224ff830f2841fd9481e33894b29f3c156f5aa Mon Sep 17 00:00:00 2001 From: okan Date: Fri, 9 Nov 2012 03:52:02 +0000 Subject: [PATCH 12/20] sort --- calmwm.c | 2 +- client.c | 2 +- conf.c | 2 +- font.c | 2 +- group.c | 2 +- kbfunc.c | 2 +- menu.c | 4 ++-- mousefunc.c | 2 +- screen.c | 2 +- search.c | 4 ++-- util.c | 2 +- xevents.c | 2 +- xmalloc.c | 2 +- xutil.c | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/calmwm.c b/calmwm.c index f908a04..f95e811 100644 --- a/calmwm.c +++ b/calmwm.c @@ -27,9 +27,9 @@ #include #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/client.c b/client.c index c2da98c..57f2218 100644 --- a/client.c +++ b/client.c @@ -24,9 +24,9 @@ #include #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/conf.c b/conf.c index 7e1f3e2..f830ef5 100644 --- a/conf.c +++ b/conf.c @@ -24,9 +24,9 @@ #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/font.c b/font.c index 88d6519..3793e55 100644 --- a/font.c +++ b/font.c @@ -23,9 +23,9 @@ #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/group.c b/group.c index cf431c6..fd507be 100644 --- a/group.c +++ b/group.c @@ -25,9 +25,9 @@ #include #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/kbfunc.c b/kbfunc.c index c67222e..e8ab152 100644 --- a/kbfunc.c +++ b/kbfunc.c @@ -26,9 +26,9 @@ #include #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/menu.c b/menu.c index 0fff91e..b6d0724 100644 --- a/menu.c +++ b/menu.c @@ -22,13 +22,13 @@ #include #include +#include #include #include +#include #include #include -#include #include -#include #include "calmwm.h" diff --git a/mousefunc.c b/mousefunc.c index 3521d71..d61adca 100644 --- a/mousefunc.c +++ b/mousefunc.c @@ -24,9 +24,9 @@ #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/screen.c b/screen.c index 69a638a..b52856f 100644 --- a/screen.c +++ b/screen.c @@ -23,9 +23,9 @@ #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/search.c b/search.c index e19c9c8..d016d12 100644 --- a/search.c +++ b/search.c @@ -25,11 +25,11 @@ #include #include #include +#include +#include #include #include -#include #include -#include #include "calmwm.h" diff --git a/util.c b/util.c index 54faaea..f69f880 100644 --- a/util.c +++ b/util.c @@ -23,9 +23,9 @@ #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/xevents.c b/xevents.c index 0d91067..e167189 100644 --- a/xevents.c +++ b/xevents.c @@ -30,9 +30,9 @@ #include #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/xmalloc.c b/xmalloc.c index 27114d1..1d0c581 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -23,9 +23,9 @@ #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/xutil.c b/xutil.c index 110ce87..9c80dfe 100644 --- a/xutil.c +++ b/xutil.c @@ -23,9 +23,9 @@ #include #include +#include #include #include -#include #include #include "calmwm.h" From 587d623e4a0a2173b5b0596107206a6ce1be99db Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 14 Nov 2012 21:12:24 +0000 Subject: [PATCH 13/20] tab-complete buglet fix: once exec_path is completed, allow for subsequent completion; from Alexander Polakov --- menu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/menu.c b/menu.c index b6d0724..e2b6e0e 100644 --- a/menu.c +++ b/menu.c @@ -299,12 +299,10 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq, if ((mi = TAILQ_FIRST(resultq)) != NULL) { /* * - We are in exec_path menu mode - * - There's only one result * - It is equal to the input * We got a command, launch the file menu */ if ((mc->flags & CWM_MENU_FILE) && - (TAILQ_NEXT(mi, resultentry) == NULL) && (strncmp(mc->searchstr, mi->text, strlen(mi->text))) == 0) return (menu_complete_path(mc)); From 7b00e3fe76148403292f2332b2398d24a16d0453 Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 14 Nov 2012 21:31:53 +0000 Subject: [PATCH 14/20] variable name consistency; from Thomas Pfaff --- conf.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/conf.c b/conf.c index f830ef5..b4967e4 100644 --- a/conf.c +++ b/conf.c @@ -446,16 +446,15 @@ conf_bindname(struct conf *c, char *name, char *binding) { struct keybinding *current_binding; char *substring, *tmp; - int iter; + int i; current_binding = xcalloc(1, sizeof(*current_binding)); if ((substring = strchr(name, '-')) != NULL) { - for (iter = 0; iter < nitems(bind_mods); iter++) { - if ((tmp = strchr(name, bind_mods[iter].chr)) != + for (i = 0; i < nitems(bind_mods); i++) { + if ((tmp = strchr(name, bind_mods[i].chr)) != NULL && tmp < substring) { - current_binding->modmask |= - bind_mods[iter].mask; + current_binding->modmask |= bind_mods[i].mask; } } @@ -487,13 +486,13 @@ conf_bindname(struct conf *c, char *name, char *binding) return; } - for (iter = 0; iter < nitems(name_to_kbfunc); iter++) { - if (strcmp(name_to_kbfunc[iter].tag, binding) != 0) + for (i = 0; i < nitems(name_to_kbfunc); i++) { + if (strcmp(name_to_kbfunc[i].tag, binding) != 0) continue; - current_binding->callback = name_to_kbfunc[iter].handler; - current_binding->flags = name_to_kbfunc[iter].flags; - current_binding->argument = name_to_kbfunc[iter].argument; + current_binding->callback = name_to_kbfunc[i].handler; + current_binding->flags = name_to_kbfunc[i].flags; + current_binding->argument = name_to_kbfunc[i].argument; conf_grab(c, current_binding); TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry); return; @@ -548,16 +547,15 @@ conf_mousebind(struct conf *c, char *name, char *binding) struct mousebinding *current_binding; char *substring, *tmp; const char *errstr; - int iter; + int i; current_binding = xcalloc(1, sizeof(*current_binding)); if ((substring = strchr(name, '-')) != NULL) { - for (iter = 0; iter < nitems(bind_mods); iter++) { - if ((tmp = strchr(name, bind_mods[iter].chr)) != + for (i = 0; i < nitems(bind_mods); i++) { + if ((tmp = strchr(name, bind_mods[i].chr)) != NULL && tmp < substring) { - current_binding->modmask |= - bind_mods[iter].mask; + current_binding->modmask |= bind_mods[i].mask; } } @@ -578,12 +576,12 @@ conf_mousebind(struct conf *c, char *name, char *binding) return; } - for (iter = 0; iter < nitems(name_to_mousefunc); iter++) { - if (strcmp(name_to_mousefunc[iter].tag, binding) != 0) + for (i = 0; i < nitems(name_to_mousefunc); i++) { + if (strcmp(name_to_mousefunc[i].tag, binding) != 0) continue; - current_binding->context = name_to_mousefunc[iter].context; - current_binding->callback = name_to_mousefunc[iter].handler; + current_binding->context = name_to_mousefunc[i].context; + current_binding->callback = name_to_mousefunc[i].handler; TAILQ_INSERT_TAIL(&c->mousebindingq, current_binding, entry); return; } From 93f64ffc55d29947614f234a5c6deddcbc2d4e81 Mon Sep 17 00:00:00 2001 From: okan Date: Fri, 16 Nov 2012 14:15:48 +0000 Subject: [PATCH 15/20] add some checks --- xmalloc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xmalloc.c b/xmalloc.c index 1d0c581..d0697fa 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,8 @@ xmalloc(size_t siz) { void *p; + if (siz == 0) + errx(1, "xmalloc: zero size"); if ((p = malloc(siz)) == NULL) err(1, "malloc"); @@ -46,6 +49,10 @@ xcalloc(size_t no, size_t siz) { void *p; + if (siz == 0 || no == 0) + errx(1, "xcalloc: zero size"); + if (SIZE_MAX / no < siz) + errx(1, "xcalloc: no * siz > SIZE_MAX"); if ((p = calloc(no, siz)) == NULL) err(1, "calloc"); From 9088b86b140767416c5ddfd12cf269cb1421a927 Mon Sep 17 00:00:00 2001 From: Christian Neukirchen Date: Mon, 26 Nov 2012 16:26:41 +0100 Subject: [PATCH 16/20] Vendor OpenBSD queue.h,v 1.36 --- queue.h | 568 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 568 insertions(+) create mode 100644 queue.h diff --git a/queue.h b/queue.h new file mode 100644 index 0000000..5442699 --- /dev/null +++ b/queue.h @@ -0,0 +1,568 @@ +/* $OpenBSD: "queue.h",v 1.36 2012/04/11 13:29:14 naddy Exp $ */ +/* $NetBSD: "queue.h",v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. + * + * @(#)"queue.h" 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST(head); \ + (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST(head); \ + (var) && ((tvar) = LIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SIMPLEQ_FIRST(head); \ + (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ + == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_NEXT(var, field), 1); \ + (var) = (tvar)) + + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = CIRCLEQ_LAST(head, headname); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ From b4315a3fdad8dc66e649a4df89617160943ae144 Mon Sep 17 00:00:00 2001 From: Christian Neukirchen Date: Mon, 26 Nov 2012 16:27:22 +0100 Subject: [PATCH 17/20] Use vendored queue.h everywhere --- calmwm.c | 2 +- client.c | 2 +- conf.c | 2 +- font.c | 2 +- group.c | 2 +- kbfunc.c | 2 +- menu.c | 2 +- mousefunc.c | 2 +- screen.c | 2 +- search.c | 2 +- util.c | 2 +- xevents.c | 2 +- xmalloc.c | 2 +- xutil.c | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/calmwm.c b/calmwm.c index f95e811..08d0b53 100644 --- a/calmwm.c +++ b/calmwm.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/client.c b/client.c index 57f2218..455f5ef 100644 --- a/client.c +++ b/client.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/conf.c b/conf.c index b4967e4..857ccb5 100644 --- a/conf.c +++ b/conf.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/font.c b/font.c index 3793e55..58dba5f 100644 --- a/font.c +++ b/font.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/group.c b/group.c index fd507be..834fac4 100644 --- a/group.c +++ b/group.c @@ -20,7 +20,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/kbfunc.c b/kbfunc.c index e8ab152..c110a9f 100644 --- a/kbfunc.c +++ b/kbfunc.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/menu.c b/menu.c index e2b6e0e..dcf801d 100644 --- a/menu.c +++ b/menu.c @@ -20,7 +20,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/mousefunc.c b/mousefunc.c index d61adca..37dd7a1 100644 --- a/mousefunc.c +++ b/mousefunc.c @@ -20,7 +20,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/screen.c b/screen.c index b52856f..c723378 100644 --- a/screen.c +++ b/screen.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/search.c b/search.c index d016d12..815f6bb 100644 --- a/search.c +++ b/search.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/util.c b/util.c index f69f880..c175165 100644 --- a/util.c +++ b/util.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/xevents.c b/xevents.c index e167189..acfb2bc 100644 --- a/xevents.c +++ b/xevents.c @@ -25,7 +25,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/xmalloc.c b/xmalloc.c index d0697fa..a93393f 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include diff --git a/xutil.c b/xutil.c index 9c80dfe..fa3fc7f 100644 --- a/xutil.c +++ b/xutil.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include From fad4798e5be4fb560c70c6f0e68aa576c28b85a4 Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 28 Nov 2012 14:14:44 +0000 Subject: [PATCH 18/20] replace hand rolled font_make() with XftFontOpenName() and merge into font_init(). --- calmwm.h | 4 ++-- conf.c | 3 +-- font.c | 24 +++++------------------- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/calmwm.h b/calmwm.h index 8c06db4..5085807 100644 --- a/calmwm.h +++ b/calmwm.h @@ -446,9 +446,9 @@ int font_descent(struct screen_ctx *); void font_draw(struct screen_ctx *, const char *, int, Drawable, int, int); u_int font_height(struct screen_ctx *); -void font_init(struct screen_ctx *, const char *); +void font_init(struct screen_ctx *, const char *, + const char *); int font_width(struct screen_ctx *, const char *, int); -XftFont *font_make(struct screen_ctx *, const char *); void xev_loop(void); diff --git a/conf.c b/conf.c index b4967e4..2fe7363 100644 --- a/conf.c +++ b/conf.c @@ -62,8 +62,7 @@ conf_gap(struct conf *c, struct screen_ctx *sc) void conf_font(struct conf *c, struct screen_ctx *sc) { - font_init(sc, c->color[CWM_COLOR_FONT].name); - sc->font = font_make(sc, c->font); + font_init(sc, c->font, c->color[CWM_COLOR_FONT].name); } static struct color color_binds[] = { diff --git a/font.c b/font.c index 3793e55..0e1c144 100644 --- a/font.c +++ b/font.c @@ -49,7 +49,7 @@ font_height(struct screen_ctx *sc) } void -font_init(struct screen_ctx *sc, const char *color) +font_init(struct screen_ctx *sc, const char *name, const char *color) { sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin, DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which)); @@ -59,6 +59,10 @@ font_init(struct screen_ctx *sc, const char *color) if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor)) errx(1, "XftColorAllocName"); + + sc->font = XftFontOpenName(X_Dpy, sc->which, name); + if (sc->font == NULL) + errx(1, "XftFontOpenName"); } int @@ -80,21 +84,3 @@ font_draw(struct screen_ctx *sc, const char *text, int len, XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor, sc->font, x, y, (const FcChar8*)text, len); } - -XftFont * -font_make(struct screen_ctx *sc, const char *name) -{ - XftFont *fn = NULL; - FcPattern *pat, *patx; - XftResult res; - - if ((pat = FcNameParse((const FcChar8*)name)) == NULL) - return (NULL); - - if ((patx = XftFontMatch(X_Dpy, sc->which, pat, &res)) != NULL) - fn = XftFontOpenPattern(X_Dpy, patx); - - FcPatternDestroy(pat); - - return (fn); -} From 2b9d921edaa665f896cf29bf6ba332c6ac11dd21 Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 28 Nov 2012 14:25:05 +0000 Subject: [PATCH 19/20] ever since the 9wm code bits were removed or replaced, this file has been a no-op, for each source file has a complete license marker (ISC). no objections from oga, who did the 9wm rewrite/remove work in 2008. --- LICENSE | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index de3b872..0000000 --- a/LICENSE +++ /dev/null @@ -1,14 +0,0 @@ - Copyright (c) 2004,2005 Marius Aamodt Eriksen - Copyright (c) 2004 Andy Adamson - - Permission to use, copy, modify, and distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. From 3e151f8c764a5f1116fae3bea87f3d4474dc686a Mon Sep 17 00:00:00 2001 From: okan Date: Wed, 28 Nov 2012 14:32:44 +0000 Subject: [PATCH 20/20] add xasprintf() for upcoming changes. --- calmwm.h | 3 +++ xmalloc.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/calmwm.h b/calmwm.h index 5085807..1abcbef 100644 --- a/calmwm.h +++ b/calmwm.h @@ -492,6 +492,9 @@ void u_spawn(char *); void *xcalloc(size_t, size_t); void *xmalloc(size_t); char *xstrdup(const char *); +int xasprintf(char **, const char *, ...) + __attribute__((__format__ (printf, 2, 3))) + __attribute__((__nonnull__ (2))); /* Externs */ extern Display *X_Dpy; diff --git a/xmalloc.c b/xmalloc.c index d0697fa..0480c73 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -69,3 +69,19 @@ xstrdup(const char *str) return (p); } + +int +xasprintf(char **ret, const char *fmt, ...) +{ + va_list ap; + int i; + + va_start(ap, fmt); + i = vasprintf(ret, fmt, ap); + va_end(ap); + + if (i < 0 || *ret == NULL) + err(1, "asprintf"); + + return (i); +}