diff options
-rw-r--r-- | Makefile | 56 | ||||
-rw-r--r-- | README | 136 | ||||
-rw-r--r-- | calmwm.c | 12 | ||||
-rw-r--r-- | calmwm.h | 23 | ||||
-rw-r--r-- | client.c | 2 | ||||
-rw-r--r-- | conf.c | 2 | ||||
-rw-r--r-- | cwm.pub | 2 | ||||
-rw-r--r-- | group.c | 2 | ||||
-rw-r--r-- | kbfunc.c | 7 | ||||
-rw-r--r-- | menu.c | 2 | ||||
-rwxr-xr-x | migrate-config.pl | 74 | ||||
-rw-r--r-- | parse.y | 6 | ||||
-rw-r--r-- | queue.h | 648 | ||||
-rw-r--r-- | reallocarray.c | 38 | ||||
-rw-r--r-- | screen.c | 2 | ||||
-rw-r--r-- | search.c | 2 | ||||
-rw-r--r-- | strlcat.c | 62 | ||||
-rw-r--r-- | strlcpy.c | 57 | ||||
-rw-r--r-- | strtonum.c | 70 | ||||
-rwxr-xr-x | update.sh | 2 | ||||
-rw-r--r-- | util.c | 2 | ||||
-rw-r--r-- | xevents.c | 2 | ||||
-rw-r--r-- | xmalloc.c | 2 | ||||
-rw-r--r-- | xutil.c | 2 |
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> |