about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile56
-rw-r--r--README136
-rw-r--r--calmwm.c12
-rw-r--r--calmwm.h23
-rw-r--r--client.c2
-rw-r--r--conf.c2
-rw-r--r--cwm.pub2
-rw-r--r--group.c2
-rw-r--r--kbfunc.c7
-rw-r--r--menu.c2
-rwxr-xr-xmigrate-config.pl74
-rw-r--r--parse.y6
-rw-r--r--queue.h648
-rw-r--r--reallocarray.c38
-rw-r--r--screen.c2
-rw-r--r--search.c2
-rw-r--r--strlcat.c62
-rw-r--r--strlcpy.c57
-rw-r--r--strtonum.c70
-rwxr-xr-xupdate.sh2
-rw-r--r--util.c2
-rw-r--r--xevents.c2
-rw-r--r--xmalloc.c2
-rw-r--r--xutil.c2
24 files changed, 1181 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index 78353dd..1f56cd4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,24 +1,54 @@
-# $OpenBSD$
-
-.include <bsd.xconf.mk>
+# cwm makefile for BSD make and GNU make
+# uses pkg-config, DESTDIR and PREFIX
 
 PROG=		cwm
 
+PREFIX?=	/usr/local
+
 SRCS=		calmwm.c screen.c xmalloc.c client.c menu.c \
 		search.c util.c xutil.c conf.c xevents.c group.c \
 		kbfunc.c parse.y
 
-CPPFLAGS+=	-I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR}
+OBJS=		calmwm.o screen.o xmalloc.o client.o menu.o \
+		search.o util.o xutil.o conf.o xevents.o group.o \
+		kbfunc.o strlcpy.o strlcat.o parse.o \
+		strtonum.o reallocarray.o
+		
+PKG_CONFIG?=	pkg-config
+
+CPPFLAGS+=	`${PKG_CONFIG} --cflags x11 xft xrandr`
+
+CFLAGS?=	-Wall -O2 -g -D_GNU_SOURCE
+
+LDFLAGS+=	`${PKG_CONFIG} --libs x11 xft xrandr`
+
+MANPREFIX?=	${PREFIX}/share/man
+
+all: ${PROG}
+
+clean:
+	rm -f ${OBJS} ${PROG} parse.c
+
+${PROG}: ${OBJS}
+	${CC} ${OBJS} ${LDFLAGS} -o ${PROG}
+
+.c.o:
+	${CC} -c ${CFLAGS} ${CPPFLAGS} $<
 
-CFLAGS+=	-Wall
-YFLAGS=
-LDADD+=		-L${X11BASE}/lib -lXft -lXrender -lX11 -lxcb -lXau -lXdmcp \
-		-lfontconfig -lexpat -lfreetype -lz -lXrandr -lXext
+install: ${PROG}
+	install -d ${DESTDIR}${PREFIX}/bin ${DESTDIR}${MANPREFIX}/man1 ${DESTDIR}${MANPREFIX}/man5
+	install -m 755 cwm ${DESTDIR}${PREFIX}/bin
+	install -m 644 cwm.1 ${DESTDIR}${MANPREFIX}/man1
+	install -m 644 cwmrc.5 ${DESTDIR}${MANPREFIX}/man5
 
-MANDIR=		${X11BASE}/man/man
-MAN=		cwm.1 cwmrc.5
+release:
+	VERSION=$$(git describe --tags | sed 's/^v//;s/-[^.]*$$//') && \
+	git archive --prefix=cwm-$$VERSION/ -o cwm-$$VERSION.tar.gz HEAD
 
-obj: _xenocara_obj
+sign:
+	VERSION=$$(git describe --tags | sed 's/^v//;s/-[^.]*$$//') && \
+	gpg2 --armor --detach-sign cwm-$$VERSION.tar.gz && \
+	signify -S -s ~/.signify/cwm.sec -m cwm-$$VERSION.tar.gz && \
+	sed -i '1cuntrusted comment: verify with cwm.pub' cwm-$$VERSION.tar.gz.sig
 
-.include <bsd.prog.mk>
-.include <bsd.xorg.mk>
+.PRECIOUS: parse.c
diff --git a/README b/README
new file mode 100644
index 0000000..04880a8
--- /dev/null
+++ b/README
@@ -0,0 +1,136 @@
+This is a port of OpenBSD's excellent cwm[0] to Linux and other Unices.
+
+    cwm is a window manager for X11 which contains many features that
+    concentrate on the efficiency and transparency of window
+    management.  cwm also aims to maintain the simplest and most
+    pleasant aesthetic.
+
+This port requires pkg-config, Xft, Xinerama and Xrandr.  The included Makefile
+should work with both GNU make and BSD make.  It has been built successfully on
+OpenBSD, FreeBSD, NetBSD, OS X 10.9 and Linux.
+
+This version actively tracks changes in the OpenBSD CVS repository.
+Releases are roughly coordinated.
+
+The revision controlled version is at https://github.com/leahneukirchen/cwm
+Releases can be found at http://leahneukirchen.org/releases
+
+You are welcome to join the IRC channel ##cwm on irc.libera.chat
+to talk about cwm.
+
+
+ChangeLog:
+
+2012-05-02: First public release 5.1 of portable cwm.
+
+2014-04-13: Second public release 5.5 of portable cwm.
+
+User visible changes (for a full list including smaller bug fixes, see
+http://www.openbsd.org/plus.html ff.)
+
+Changes made between OpenBSD 5.1 and 5.2
+* Fixed cwm(1) atom (WM_PROTOCOLS) style handing; closing a window will no
+  longer close entire application if the client supports CLIENT_PROTO_DELETE.
+* Re-implement atom handing for more consistent separation of cwm(1) and
+  Extended Window Manager Hints.
+* cwm(1) better integrated into the freedesktop.org Window Manager
+  Specification Project.
+
+Changes made between OpenBSD 5.2 and 5.3
+* Set the initial cwm(1) group to "1".
+* Added cwm(1) per-group vert/horiz tiling support with new bind commands
+  "vtile" and "htile."
+* Made cwm(1) screen font an Xft(3) font.
+* Specific last match for autogroup in cwmrc(5).
+* Tab completion support for cwm(1) menus.
+* Allow cwm(1) clients to be resized from a max state.
+* Multibyte input to cwm(1) menu code now possible.
+
+Changes made between OpenBSD 5.3 and 5.4
+* Added support for mouse based group {,r}cycle to cwmrc(5).
+* Allow mouse button4 and button5 in cwmrc(5).
+* Made cwm(1) check for, and honour, CWStackMode and CWSibling change requests
+  during a ConfigureRequest event.
+* Honour PATH search order for cwm(1)'s exec.
+
+Changes made between OpenBSD 5.5 and 5.4
+* Only set the cwm(1) urgency flag if the client is not active.
+* Allow the cwm(1) config parser continue parsing even after encountering an
+  error.
+* cwm(1) now follows the EWMH spec: if the cardinal returned is 0xFFFFFFFF (-1)
+  then the window should appear on all desktops.
+* Made cwm(1) supply a more useful title for windows launched via the ssh(1)
+  command menu ("[ssh] ").
+* Allowed cwm(1) to accept _NET_WM_DESKTOP and _NET_CURRENT_DESKTOP
+  ClientMessage.
+* Implemented cwm(1) support for _NET_WM_STATE_FULLSCREEN hint, with keybinding
+  changes: CM-f "fullscreen", CM-m "maximize".
+* Instead of using the work area, use the Xinerama area for cwm(1) snap
+  calculations.
+* Save-set when cwm(1) is re-exec'ing so as to not lose State on our hidden
+  clients.
+* Added cwmrc(5) support for XUrgency and matching
+  _NET_WM_STATE_DEMANDS_ATTENTION ewmh hint, with configurable urgencyborder.
+* Prepend the group shortcut in the cwm(1) client search menu;
+  prepend shortcut in unhide menu.
+* If not hidden during an UnmapNotify event, cwm(1) will now un-manage the
+  client.
+* Like "gap", made cwm(1) "snapdist" per-screen.
+* Removed cwmrc(5) option to bind a key by keycode with brackets, which never
+  worked. Users should be using keysym names not keycodes.
+* Re-added cwm(1) support for WM_TAKE_FOCUS. Solves keyboard input focus loss
+  for java apps.
+* For cwm(1) clients that support WM_TAKE_FOCUS in their WM_PROTOCOLS property,
+  send a ClientMessage event.
+
+2015-01-24: Third public release 5.6 of portable cwm.
+
+* Support building on FreeBSD and OS X.
+* Support for sticky windows (_NET_WM_STATE_STICKY).
+* Internal cleanups and bug fixes.
+
+Changes made between OpenBSD 5.6 and 5.7
+* Implemented _NET_WM_STATE_STICKY in cwm(1). Allows client to "stick"
+  to all desktops or groups.
+* Ensure cwm(1) client that wants to be in nogroup stays in nogroup
+  (thus stays in view), even when (re)reading NET_WM_DESKTOP. 
+
+Changes made between OpenBSD 5.7 and 5.8
+* In cwm(1), introduce "groupsearch" for group menu search. 
+* In cwm(1), show an empty "ssh to" menu if the known_hosts file is missing. 
+* In cwm(1), replace screen region info gathering with XRandR
+  equivalent of Xinerama queries. 
+
+Changes made between OpenBSD 5.8 and 5.9
+* Don't allow freeze operations on fullscreen.
+* Implement _NET_CLIENT_LIST_STACKING. 
+
+2017-10-17: Fourth public release 6.2 of portable cwm.
+
+Changes made between OpenBSD 6.2 and 6.3
+* Fix blocking bug during moving or resizing.
+* window-snap-* commands to move windows to edges and corners.
+* Add support for _NET_WM_STATE_SKIP_PAGER and _NET_WM_STATE_SKIP_TASKBAR.
+* Add support for re-exec'ing with SIGHUP.
+
+2018-05-14: Fifth public release 6.3 of portable cwm.
+
+2020-01-04: Sixth public release 6.6 of portable cwm.
+
+Changes made between OpenBSD 6.4 and 6.5
+* Added a configtest flag (-n) to cwm(1).
+* Introduced 'group-close-[n]' action to cwm(1) to close all windows
+  within a specified group.
+
+2020-05-22: Seventh public release 6.7 of portable cwm.
+
+Changes made between OpenBSD 6.6 and 6.7
+* Allowed cwm(1) configuration of window size based on percentage of
+  the master window during horizontal and vertical tiling actions.
+* Allowed use of window-htile and window-vtile with the "empty" group
+  clients in cwm(1).
+
+
+--Leah Neukirchen <leah@vuxu.org>
+
+[0]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/xenocara/app/cwm/
diff --git a/calmwm.c b/calmwm.c
index f81a2f6..39f53d8 100644
--- a/calmwm.c
+++ b/calmwm.c
@@ -19,7 +19,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 #include <sys/wait.h>
 
 #include <err.h>
@@ -44,7 +44,7 @@ struct screen_q		 Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
 struct conf		 Conf;
 volatile sig_atomic_t	 cwm_status;
 
-__dead void	usage(void);
+void	usage(void);
 static void	sighdlr(int);
 static int	x_errorhandler(Display *, XErrorEvent *);
 static int	x_init(const char *);
@@ -106,15 +106,17 @@ main(int argc, char **argv)
 	xfd = x_init(display_name);
 	cwm_status = CWM_RUNNING;
 
+#ifdef __OpenBSD__
 	if (pledge("stdio rpath proc exec", NULL) == -1)
 		err(1, "pledge");
+#endif
 
 	memset(&pfd, 0, sizeof(pfd));
 	pfd[0].fd = xfd;
 	pfd[0].events = POLLIN;
 	while (cwm_status == CWM_RUNNING) {
 		xev_process();
-		if (poll(pfd, 1, INFTIM) == -1) {
+		if (poll(pfd, 1, -1) == -1) {
 			if (errno != EINTR)
 				warn("poll");
 		}
@@ -210,7 +212,7 @@ sighdlr(int sig)
 	switch (sig) {
 	case SIGCHLD:
 		/* Collect dead children. */
-		while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0 ||
+		while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
 		    (pid < 0 && errno == EINTR))
 			;
 		break;
@@ -226,7 +228,7 @@ sighdlr(int sig)
 	errno = save_errno;
 }
 
-__dead void
+void
 usage(void)
 {
 	extern char	*__progname;
diff --git a/calmwm.h b/calmwm.h
index 7c428f6..b3992c3 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -21,6 +21,27 @@
 #ifndef _CALMWM_H_
 #define _CALMWM_H_
 
+#include <sys/param.h>
+#include <stdio.h>
+#include "queue.h"
+
+/* prototypes for portable-included functions */
+char *fgetln(FILE *, size_t *);
+long long strtonum(const char *, long long, long long, const char **);
+void *reallocarray(void *, size_t, size_t);
+
+
+#ifdef strlcat
+#define HAVE_STRLCAT
+#else
+size_t strlcat(char *, const char *, size_t);
+#endif
+#ifdef strlcpy
+#define HAVE_STRLCPY
+#else
+size_t strlcpy(char *, const char *, size_t);
+#endif
+
 #include <X11/XKBlib.h>
 #include <X11/Xatom.h>
 #include <X11/Xft/Xft.h>
@@ -397,6 +418,8 @@ extern Atom				 ewmh[EWMH_NITEMS];
 extern struct screen_q			 Screenq;
 extern struct conf			 Conf;
 
+void			 usage(void);
+
 void			 client_apply_sizehints(struct client_ctx *);
 void			 client_close(struct client_ctx *);
 void			 client_config(struct client_ctx *);
diff --git a/client.c b/client.c
index 9ec2935..59bc7b0 100644
--- a/client.c
+++ b/client.c
@@ -19,7 +19,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <err.h>
 #include <errno.h>
diff --git a/conf.c b/conf.c
index 7610400..7d3ae6e 100644
--- a/conf.c
+++ b/conf.c
@@ -19,7 +19,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <err.h>
 #include <errno.h>
diff --git a/cwm.pub b/cwm.pub
new file mode 100644
index 0000000..fd16529
--- /dev/null
+++ b/cwm.pub
@@ -0,0 +1,2 @@
+untrusted comment: portable cwm release key public key
+RWTdOib0PoIM0pmDAPnV2S9/AMRqTOVfTY/KAkFemdH13cqBDHdduTas
diff --git a/group.c b/group.c
index 3246936..af4c759 100644
--- a/group.c
+++ b/group.c
@@ -20,7 +20,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <err.h>
 #include <errno.h>
diff --git a/kbfunc.c b/kbfunc.c
index f805360..ed1d7cb 100644
--- a/kbfunc.c
+++ b/kbfunc.c
@@ -18,8 +18,11 @@
  * $OpenBSD$
  */
 
+/* For FreeBSD. */
+#define _WITH_GETLINE
+
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 #include <sys/stat.h>
 
 #include <dirent.h>
@@ -709,7 +712,7 @@ kbfunc_menu_ssh(void *ctx, struct cargs *cargs)
 	struct menu_q		 menuq;
 	FILE			*fp;
 	char			*buf, *lbuf, *p;
-	char			 hostbuf[HOST_NAME_MAX+1];
+	char			 hostbuf[_POSIX_HOST_NAME_MAX+1];
 	char			 path[PATH_MAX];
 	int			 l;
 	size_t			 len;
diff --git a/menu.c b/menu.c
index 43b5de8..1d84ab7 100644
--- a/menu.c
+++ b/menu.c
@@ -20,7 +20,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <ctype.h>
 #include <err.h>
diff --git a/migrate-config.pl b/migrate-config.pl
new file mode 100755
index 0000000..9144912
--- /dev/null
+++ b/migrate-config.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl -p
+# Originally by Stuart Henderson in
+# <20161206120601.vmimohqh4nafaeah@symphytum.spacehopper.org>
+# Ported to Perl and slightly tweaked by Leah Neukirchen.
+
+s/\bbind\b(.*)\bunmap/unbind-key \1/;
+s/\bmousebind\b(.*)unmap/unbind-mouse \1/;
+s/\bresize\b/window-resize/;
+s/\bresizedown\b/window-resize-down/;
+s/\bresizeleft\b/window-resize-left/;
+s/\bresizeright\b/window-resize-right/;
+s/\bresizeup\b/window-resize-up/;
+s/\bmove\b/window-move/;
+s/\bmovedown\b/window-move-down/;
+s/\bmoveleft\b/window-move-left/;
+s/\bmoveright\b/window-move-right/;
+s/\bmoveup\b/window-move-up/;
+s/\bbigmovedown\b/window-move-down-big/;
+s/\bbigmoveleft\b/window-move-left-big/;
+s/\bbigmoveright\b/window-move-right-big/;
+s/\bbigmoveup\b/window-move-up-big/;
+s/\bbigptrmovedown\b/pointer-move-down-big/;
+s/\bbigptrmoveleft\b/pointer-move-left-big/;
+s/\bbigptrmoveright\b/pointer-move-right-big/;
+s/\bbigptrmoveup\b/pointer-move-up-big/;
+s/\bbigresizedown\b/window-resize-down-big/;
+s/\bbigresizeleft\b/window-resize-left-big/;
+s/\bbigresizeright\b/window-resize-right-big/;
+s/\bbigresizeup\b/window-resize-up-big/;
+s/\bbind\b/bind-key/;
+s/\bcycle\b/window-cycle/;
+s/\bcyclegroup\b/group-cycle/;
+s/\bcycleingroup\b/window-cycle-ingroup/;
+s/\bdelete\b/window-delete/;
+s/\bexec\b/menu-exec/;
+s/\bexec_wm\b/menu-exec-wm/;
+s/\bfreeze\b/window-freeze/;
+s/\bfullscreen\b/window-fullscreen/;
+s/\bgroupsearch\b/menu-group/;
+s/\bgrouptoggle\b/window-group/;
+s/\bhide\b/window-hide/;
+s/\bhmaximize\b/window-hmaximize/;
+s/\bhtile\b/window-htile/;
+s/\blabel\b/window-menu-label/;
+s/\blower\b/window-lower/;
+s/\bmaximize\b/window-maximize/;
+s/\bmenu_cmd\b/menu-cmd/;
+s/\bmenu_group\b/menu-group/;
+s/\bmenu_unhide\b/menu-window/;
+s/\bmenusearch\b/menu-cmd/;
+s/\bmousebind\b/bind-mouse/;
+s/\bnogroup\b/group-toggle-all/;
+s/\bptrmovedown\b/pointer-move-down/;
+s/\bptrmoveleft\b/pointer-move-left/;
+s/\bptrmoveright\b/pointer-move-right/;
+s/\bptrmoveup\b/pointer-move-up/;
+s/\braise\b/window-raise/;
+s/\brcycle\b/window-rcycle/;
+s/\brcyclegroup\b/group-rcycle/;
+s/\brcycleingroup\b/window-rcycle-ingroup/;
+s/\bsearch\b/menu-window/;
+s/\bssh\b/menu-ssh/;
+s/\bstick\b/window-stick/;
+s/\bvmaximize\b/window-vmaximize/;
+s/\bvtile\b/window-vtile/;
+s/\bwindow_grouptoggle\b/window-group/;
+s/\bwindow_move\b/window-move/;
+s/\bwindow_resize\b/window-resize/;
+s/\bwindow_hide\b/window-hide/;
+s/\bwindow_lower\b/window-lower/;
+s/\bwindow_raise\b/window-raise/;
+s/\bmovetogroup([1-9])\b/window-movetogroup-\1/;
+s/\bgrouponly([1-9])\b/group-only-\1/;
+s/\bgroup([1-9])\b/group-toggle-\1/;
diff --git a/parse.y b/parse.y
index a451da5..d0407a7 100644
--- a/parse.y
+++ b/parse.y
@@ -22,7 +22,7 @@
 %{
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <ctype.h>
 #include <err.h>
@@ -35,6 +35,8 @@
 
 #include "calmwm.h"
 
+#define YYSTYPE_IS_DECLARED
+
 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
 static struct file {
 	TAILQ_ENTRY(file)	 entry;
@@ -513,7 +515,7 @@ yylex(void)
 				yyerror("string too long");
 				return (findeol());
 			}
-			*p++ = c;
+			*p++ = (char)c;
 		}
 		yylval.v.string = xstrdup(buf);
 		return (STRING);
diff --git a/queue.h b/queue.h
new file mode 100644
index 0000000..f8f09bf
--- /dev/null
+++ b/queue.h
@@ -0,0 +1,648 @@
+/*	$OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch 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)
+
+/*
+ * XOR Simple queue definitions.
+ */
+#define XSIMPLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *sqx_first;	/* first element */			\
+	struct type **sqx_last;	/* addr of last next element */		\
+	unsigned long sqx_cookie;					\
+}
+
+#define XSIMPLEQ_ENTRY(type)						\
+struct {								\
+	struct type *sqx_next;	/* next element */			\
+}
+
+/*
+ * XOR Simple queue access methods.
+ */
+#define XSIMPLEQ_XOR(head, ptr)	    ((__typeof(ptr))((head)->sqx_cookie ^ \
+					(unsigned long)(ptr)))
+#define	XSIMPLEQ_FIRST(head)	    XSIMPLEQ_XOR(head, ((head)->sqx_first))
+#define	XSIMPLEQ_END(head)	    NULL
+#define	XSIMPLEQ_EMPTY(head)	    (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
+#define	XSIMPLEQ_NEXT(head, elm, field)    XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
+
+
+#define XSIMPLEQ_FOREACH(var, head, field)				\
+	for ((var) = XSIMPLEQ_FIRST(head);				\
+	    (var) != XSIMPLEQ_END(head);				\
+	    (var) = XSIMPLEQ_NEXT(head, var, field))
+
+#define	XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = XSIMPLEQ_FIRST(head);				\
+	    (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1);	\
+	    (var) = (tvar))
+
+/*
+ * XOR Simple queue functions.
+ */
+#define	XSIMPLEQ_INIT(head) do {					\
+	arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
+	(head)->sqx_first = XSIMPLEQ_XOR(head, NULL);			\
+	(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first);	\
+} while (0)
+
+#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.sqx_next = (head)->sqx_first) ==		\
+	    XSIMPLEQ_XOR(head, NULL))					\
+		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+	(head)->sqx_first = XSIMPLEQ_XOR(head, (elm));			\
+} while (0)
+
+#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL);		\
+	*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
+	(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);	\
+} while (0)
+
+#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.sqx_next = (listelm)->field.sqx_next) ==	\
+	    XSIMPLEQ_XOR(head, NULL))					\
+		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+	(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm));		\
+} while (0)
+
+#define XSIMPLEQ_REMOVE_HEAD(head, field) do {				\
+	if (((head)->sqx_first = XSIMPLEQ_XOR(head,			\
+	    (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
+		(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
+} while (0)
+
+#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
+	if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head,			\
+	    (elm)->field.sqx_next)->field.sqx_next)			\
+	    == XSIMPLEQ_XOR(head, NULL))				\
+		(head)->sqx_last = 					\
+		    XSIMPLEQ_XOR(head, &(elm)->field.sqx_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_ */
diff --git a/reallocarray.c b/reallocarray.c
new file mode 100644
index 0000000..ed3244e
--- /dev/null
+++ b/reallocarray.c
@@ -0,0 +1,38 @@
+/*	$OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $	*/
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW	((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+	if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+	    nmemb > 0 && SIZE_MAX / nmemb < size) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	return realloc(optr, size * nmemb);
+}
diff --git a/screen.c b/screen.c
index e880e97..8e4df53 100644
--- a/screen.c
+++ b/screen.c
@@ -19,7 +19,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <err.h>
 #include <errno.h>
diff --git a/search.c b/search.c
index 03f56e3..12dde97 100644
--- a/search.c
+++ b/search.c
@@ -19,7 +19,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <err.h>
 #include <errno.h>
diff --git a/strlcat.c b/strlcat.c
new file mode 100644
index 0000000..d94dae1
--- /dev/null
+++ b/strlcat.c
@@ -0,0 +1,62 @@
+/*	$OpenBSD: strlcat.c,v 1.14 2015/01/15 03:54:12 millert Exp $	*/
+
+/*
+ * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */
+
+#include <sys/types.h>
+#include <string.h>
+#include "calmwm.h"
+
+#ifndef HAVE_STRLCAT
+
+/*
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left).  At most dsize-1 characters
+ * will be copied.  Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t dsize)
+{
+	const char *odst = dst;
+	const char *osrc = src;
+	size_t n = dsize;
+	size_t dlen;
+
+	/* Find the end of dst and adjust bytes left but don't go past end. */
+	while (n-- != 0 && *dst != '\0')
+		dst++;
+	dlen = dst - odst;
+	n = dsize - dlen;
+
+	if (n-- == 0)
+		return(dlen + strlen(src));
+	while (*src != '\0') {
+		if (n != 0) {
+			*dst++ = *src;
+			n--;
+		}
+		src++;
+	}
+	*dst = '\0';
+
+	return(dlen + (src - osrc));	/* count does not include NUL */
+}
+
+#endif /* !HAVE_STRLCAT */
diff --git a/strlcpy.c b/strlcpy.c
new file mode 100644
index 0000000..75d7d4a
--- /dev/null
+++ b/strlcpy.c
@@ -0,0 +1,57 @@
+/*	$OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $	*/
+
+/*
+ * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */
+
+#include <sys/types.h>
+#include <string.h>
+#include "calmwm.h"
+
+#ifndef HAVE_STRLCPY
+
+/*
+ * Copy string src to buffer dst of size dsize.  At most dsize-1
+ * chars will be copied.  Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t dsize)
+{
+	const char *osrc = src;
+	size_t nleft = dsize;
+
+	/* Copy as many bytes as will fit. */
+	if (nleft != 0) {
+		while (--nleft != 0) {
+			if ((*dst++ = *src++) == '\0')
+				break;
+		}
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src. */
+	if (nleft == 0) {
+		if (dsize != 0)
+			*dst = '\0';		/* NUL-terminate dst */
+		while (*src++)
+			;
+	}
+
+	return(src - osrc - 1);	/* count does not include NUL */
+}
+
+#endif /* !HAVE_STRLCPY */
diff --git a/strtonum.c b/strtonum.c
new file mode 100644
index 0000000..cdd26b6
--- /dev/null
+++ b/strtonum.c
@@ -0,0 +1,70 @@
+/*	$OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $	*/
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */
+
+#ifndef HAVE_STRTONUM
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define	INVALID		1
+#define	TOOSMALL	2
+#define	TOOLARGE	3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+    const char **errstrp)
+{
+	long long ll = 0;
+	int error = 0;
+	char *ep;
+	struct errval {
+		const char *errstr;
+		int err;
+	} ev[4] = {
+		{ NULL,		0 },
+		{ "invalid",	EINVAL },
+		{ "too small",	ERANGE },
+		{ "too large",	ERANGE },
+	};
+
+	ev[0].err = errno;
+	errno = 0;
+	if (minval > maxval) {
+		error = INVALID;
+	} else {
+		ll = strtoll(numstr, &ep, 10);
+		if (numstr == ep || *ep != '\0')
+			error = INVALID;
+		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+			error = TOOSMALL;
+		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+			error = TOOLARGE;
+	}
+	if (errstrp != NULL)
+		*errstrp = ev[error].errstr;
+	errno = ev[error].err;
+	if (error)
+		ll = 0;
+
+	return (ll);
+}
+
+#endif /* HAVE_STRTONUM */
diff --git a/update.sh b/update.sh
new file mode 100755
index 0000000..a87b259
--- /dev/null
+++ b/update.sh
@@ -0,0 +1,2 @@
+#GIT_MERGE_AUTOEDIT=no git cvsimport -o master -v -k -m -d anoncvs@openbsd.cs.fau.de:/cvs xenocara/app/cwm
+GIT_MERGE_AUTOEDIT=no git cvsimport -o master -v -k -m -d anoncvs@mirror.osn.de:/cvs xenocara/app/cwm
diff --git a/util.c b/util.c
index 904a54c..97b5641 100644
--- a/util.c
+++ b/util.c
@@ -19,7 +19,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <err.h>
 #include <errno.h>
diff --git a/xevents.c b/xevents.c
index 1aaa929..5e138aa 100644
--- a/xevents.c
+++ b/xevents.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <err.h>
 #include <errno.h>
diff --git a/xmalloc.c b/xmalloc.c
index 211d64c..54867ae 100644
--- a/xmalloc.c
+++ b/xmalloc.c
@@ -19,7 +19,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <err.h>
 #include <errno.h>
diff --git a/xutil.c b/xutil.c
index 230a2c5..c8f74fd 100644
--- a/xutil.c
+++ b/xutil.c
@@ -19,7 +19,7 @@
  */
 
 #include <sys/types.h>
-#include <sys/queue.h>
+#include "queue.h"
 
 #include <err.h>
 #include <errno.h>