Compare commits

...

52 Commits

Author SHA1 Message Date
Guillem Jover
54796231c7 Release libbsd 0.11.4 2022-01-22 22:41:51 +01:00
Guillem Jover
7aed0edf73 man: Add missing comma in .Dd for tree(3)
Reported-by: Thorsten Glaser <tg@mirbsd.de>
2021-12-02 00:35:40 +01:00
Guillem Jover
fafcc397ac man: Update tree(3) man page from OpenBSD
This man page has a BSD-3-clause-author license instead of the old
BSD-4-clause license.
2021-12-01 04:17:11 +01:00
Guillem Jover
48107fc8c4 build: Clarify link-time warnings
Mention the involved function instead of stating an implicit "this
function". Mention libbsd when proposing using an alternative libmd
to make the context clear.
2021-12-01 04:17:11 +01:00
Guillem Jover
e7cf8c5785 Switch md5 compatibility logic back to direct linking
When using the recent dlsym() based wrapper, we are not requiring any
symbol from libmd, as we resolve those dynamically at run-time. We were
ending up linking against libmd because in another part of the code we
require (depending on the architecture) the SHA512 functions for the
getentropy() local implementation. But that function might be provided
by the system libc on some systems, which means we end up not linking
against libmd at all.

To solve this we go back to the previous simpler solution of linking
directly, which had the main drawback of then making programs fail to
link when not specifying -lmd (on platforms that need it). And then
switch the .so link point from a symlink to a linker script, so that we
can inject the -lmd library as-needed. This is similar to what glibc is
doing.

Fixes: commit 31f034e386
2021-12-01 04:14:35 +01:00
Guillem Jover
25d35625eb build: Split libmd dependency due to MD5 functions from SHA requirements
To be able to rework the md5 deprecation logic, we need to detangle when
we depend on libmd due to requiring MD5 functions, which might be
otherwise provided by libc, or when we require SHA functions for the
internal getentropy() implementation.
2021-11-28 22:40:58 +01:00
Guillem Jover
500b3080a2 build: Add new libbsd_symver_weak() macro
We will use it for the reworked md5 deprecation logic.
2021-11-28 22:34:59 +01:00
Guillem Jover
1eba406021 test: Check that strdup() does not fail
Warned-by: gcc
2021-11-27 23:42:37 +01:00
Guillem Jover
8ad7570c20 getentropy: Add missing prototype for BSD variant
Warned-by: gcc
2021-11-27 23:42:37 +01:00
Guillem Jover
43a8270317 nlist: Remove condition which is always true
The nlist() function is limited to handle ELF binaries of the same class
as size as the size_t of the architecture built.

In addition the SIZE_T_MAX macro is BSD specific, and was falling back
to the wrong constant on most 64-bit non-BSD systems.

Warned-by: gcc
2021-11-27 23:36:34 +01:00
Guillem Jover
6a71b24b63 build: Append __ after __attribute and __typeof keywords
Be consistent with other usages in the code base.
2021-11-27 22:53:32 +01:00
Guillem Jover
7389fe8d24 build: Ignore backup files 2021-11-27 06:54:49 +01:00
Victor Westerhuis
2716dfd0b7 test: Explicitly mark symbols as used
Because some of the symbols are not otherwise referenced, GCC would like
to remove them.

Closes: !14
Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-11-27 06:52:17 +01:00
Victor Westerhuis
54f8745657 build: Enable .init_array support when building with LTO
Because these symbols are not otherwise referenced, GCC would like
to remove them.

Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-11-27 06:51:02 +01:00
Guillem Jover
428be9e030 man: Fix .Nx macro usage
Its arguments are used as version numbers, so we need continue the
content on the next line.
2021-11-27 05:06:14 +01:00
Alexander Miller
c7a5d780ae build: Allow building with -flto on gcc-10 and newer
Global asm statements (like .symver directives) do not work reliably
in gcc with link time optimization. Use the symver attribute introduced
with gcc-10 to set symbol versions instead, if available.

[guillem@hadrons.org:
 - Simplify by using __has_attribute fallback from <sys/cdefs.h>.
 - Coding style changes. ]

Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-11-27 05:06:14 +01:00
Guillem Jover
1808d64b77 test: Fix pipe_feed() to allow checking fprintf format strings
Warned-by: gcc -W
2021-11-27 05:06:14 +01:00
Guillem Jover
beafad2657 build: Add missing proctitle unit test program 2021-11-27 05:06:14 +01:00
Guillem Jover
6145b56178 test: Do not pass NULL as the first funopen() argument
Warned-by: gcc -W
2021-11-27 05:06:14 +01:00
Guillem Jover
731b0a7739 build: Detect sed at configure time
Check whether sed is available and use the implementation matching the
requirements via the SED variable.
2021-11-27 05:06:14 +01:00
Guillem Jover
50b50a4330 vis: Add prototypes for strnvis() and strnunvis() variants
Warned-by: gcc
2021-11-27 05:06:14 +01:00
Guillem Jover
25e88f6479 test: Cast literal strings to (char *) on n_name assignment
The member is declared as n_name so we cannot directly assign a literal
string constant.

Warned-by: gcc
2021-11-27 05:06:14 +01:00
Guillem Jover
04a8fb2469 Add missing prototypes to functions
Warned-by: gcc
2021-11-27 05:06:14 +01:00
Guillem Jover
4f68a88f55 build: Add compiler warnings support
Detect as many warnings as possible during configure and enable them
if the user did not supply any, so that any such problem can be spotted
and fixed.
2021-11-27 05:06:14 +01:00
Guillem Jover
8f59221c4f nlist: Remove repeated shadowing variable declaration
Warned-by: gcc
2021-02-28 05:30:37 +01:00
Guillem Jover
72a82ee262 getentropy: Fix function cast for getauxval()
Warned-by: gcc
2021-02-28 05:30:37 +01:00
Guillem Jover
3c305f2873 test: Add proper prototypes for main() function
Warned-by: gcc
2021-02-28 05:30:31 +01:00
Guillem Jover
25278891d8 Mark local functions as static
Warned-by: gcc
2021-02-28 05:30:25 +01:00
Guillem Jover
e35d9141dc Add link-time warnings to MD5 wrapper functions
Let's get the word out that these functions are deprecated and should be
switched away from.
2021-02-28 05:28:57 +01:00
Guillem Jover
4feda87049 Require a semicolon for libbsd_link_warning() macro
Remove the semicolon in the macro definition to force adding one on the
call sites, to make the code look like an actual function.
2021-02-28 05:28:57 +01:00
Guillem Jover
d563a17430 man: Call the libbsd-ctor library by its name instead of bsd-ctor 2021-02-28 05:28:57 +01:00
Guillem Jover
785cf9d1e9 man: Fix pkg-config(1) references in libbsd(7) man page 2021-02-28 05:28:57 +01:00
Guillem Jover
15bd284b29 build: Add code coverage support in the GitLab CI 2021-02-28 05:28:49 +01:00
Guillem Jover
a9fc285988 build: Use apt-get instead of apt in the GitLab CI
The former is to be used programmatically, while the latter is intended
for interactive use.
2021-02-28 05:27:35 +01:00
Guillem Jover
c0d86a6412 build: Add a Libs.private field to overlay pkg-config file
We need to list all internal libraries there so that we can statically
link.

Fixes: commit 2374f409de
2021-02-09 08:36:01 +01:00
Guillem Jover
1fb25b7dca Release libbsd 0.11.3 2021-02-09 06:23:38 +01:00
Guillem Jover
31f034e386 Switch libmd wrapper to use dlsym()
Switch from the previous versioned symbol implementation which required
users to also link against the message digest provider explicitly, or
they would fail to find the symbols, to an implementation that loads
the symbols from the linked library providing the functions using
dlsym(), thus preserving backwards compatibility.
2021-02-09 06:23:38 +01:00
Guillem Jover
2374f409de build: Add a Libs.private field to pkg-config file
We need to list all internal libraries there so that we can statically
link.
2021-02-09 06:23:38 +01:00
Guillem Jover
a4e0db2b97 build: Use a single variable to track libraries to link against
Using various variables means we have to keep these in sync in various
places. Just use a single variable that we can use anywhere where this
is needed.
2021-02-09 06:23:38 +01:00
Guillem Jover
43d34c9d3b build: Fix message digest library checks
They were not failing when not finding the SHA-2 functions and
were hardcoding -lmd regardless of what library had been found.
2021-02-09 06:23:38 +01:00
Guillem Jover
1c3ff61699 Use uintptr_t and size_t instead of __-prefixed types in <sys/cdefs.h>
The __-prefixed types cannot be assumed to be defined. Use the standard
types instead.

Closes: #6
2021-02-09 06:23:27 +01:00
Guillem Jover
edea268ce9 Release libbsd 0.11.2 2021-02-08 04:02:46 +01:00
Guillem Jover
e832b7687e closefrom: Use close_range() on Linux when available
Closes: !11
Based-on-patch-by: cptpcrd <cptpcrd.git@gmail.com>
Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-02-08 04:02:46 +01:00
cptpcrd
c4fca5bb4f closefrom: Handle lowfd < 0 properly
More important if close_range() is going to be used, since casting
negative values to 'unsigned int' might hide the errors.

[guillem@hadrons.org: Minor coding style fix. ]

Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-02-08 04:02:46 +01:00
Guillem Jover
a1f79978e8 closefrom: Import some changes from sudo
Take most of the changes done in sudo, but preserve the existing local
changes and refactoring.

In addition, refactor pstat implementation into closefrom_pstat(), so
that the code is easier to read, and requires no conditional
declarations.
2021-02-08 04:02:46 +01:00
Faidon Liambotis
4676026286 Update <sys/queue.h> from FreeBSD
This brings <sys/queue.h> to the most up-to-date version from FreeBSD,
incorporating 18 commits from the past 5 years (2015-02-24 - 2021-01-25):

  $ git log --oneline 9090a24aed70..8d55837dc133 sys/sys/queue.h share/man/man3/queue.3

Only minimal changes compared to the FreeBSD version have been applied
(queue.3 -> queue.3bsd, _LIBBSD_ prefix).

[guillem@hadrons.org: Remove reference to kernel mode in man page. ]

Closes: !12
Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-02-08 04:02:16 +01:00
Guillem Jover
25f9b30678 test: Improve code coverage for strnstr(3) unit tests 2021-02-07 23:24:51 +01:00
Guillem Jover
18ebabf223 man: Update libbsd(7) man page with updates in 0.11.0 2021-02-07 15:17:33 +01:00
Guillem Jover
4ab11c7f48 build: Install libmd-dev in the gitlab CI 2021-02-07 10:37:18 +01:00
Guillem Jover
766c883e30 build: Switch gitlab CI to use a Debian buster 2021-02-07 10:35:57 +01:00
Guillem Jover
a4de4d95a6 Release libbsd 0.11.1 2021-02-07 02:03:59 +01:00
Guillem Jover
233cab9d64 Add support for new LIBBSD_VIS_OPENBSD selection macro
This will make it possible to explicitly select the OpenBSD vis
implementation (the current default) for code of OpenBSD origins.
2021-02-07 02:03:22 +01:00
53 changed files with 1016 additions and 359 deletions

5
.gitignore vendored
View File

@@ -1,4 +1,5 @@
ChangeLog ChangeLog
*~
*.pc *.pc
*.la *.la
*.lo *.lo
@@ -7,6 +8,8 @@ ChangeLog
*.a *.a
*.log *.log
*.trs *.trs
*.gcda
*.gcno
.dirstamp .dirstamp
.deps/ .deps/
.libs/ .libs/
@@ -17,6 +20,6 @@ autom4te.cache/
build-aux/ build-aux/
configure configure
config.* config.*
format.ld
libtool libtool
m4/
stamp-h1 stamp-h1

View File

@@ -1,9 +1,19 @@
image: debian:stretch image: debian:buster
test: before_script:
before_script: - apt-get update -qq
- apt update -qq - apt-get install -qq -y --no-install-recommends
- apt install -qq -y --no-install-recommends git gcc make autoconf automake libtool git gcc make autoconf automake libtool libmd-dev gcovr
unit-tests:
stage: test
script: script:
- ./autogen && ./configure - ./autogen && ./configure
- make check - make check
coverage:
stage: test
script:
- ./autogen && ./configure --disable-static
- make check CFLAGS="--coverage -O0 -ggdb" LDFLAGS="--coverage -O0 -ggdb"
- gcovr -s -e test/

View File

@@ -8,7 +8,6 @@ License: BSD-3-clause
Files: Files:
man/arc4random.3bsd man/arc4random.3bsd
man/tree.3bsd
Copyright: Copyright:
Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
All rights reserved. All rights reserved.
@@ -348,6 +347,7 @@ License: BSD-2-clause-verbatim
Files: Files:
include/bsd/sys/tree.h include/bsd/sys/tree.h
man/fparseln.3bsd man/fparseln.3bsd
man/tree.3bsd
src/fparseln.c src/fparseln.c
Copyright: Copyright:
Copyright © 1997 Christos Zoulas. Copyright © 1997 Christos Zoulas.

View File

@@ -13,7 +13,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])],
LIBBSD_ABI_MAJOR=0 LIBBSD_ABI_MAJOR=0
LIBBSD_ABI_MINOR=11 LIBBSD_ABI_MINOR=11
LIBBSD_ABI_PATCH=0 LIBBSD_ABI_PATCH=4
LIBBSD_ABI="$LIBBSD_ABI_MAJOR:$LIBBSD_ABI_MINOR:$LIBBSD_ABI_PATCH" LIBBSD_ABI="$LIBBSD_ABI_MAJOR:$LIBBSD_ABI_MINOR:$LIBBSD_ABI_PATCH"
AC_SUBST([LIBBSD_ABI]) AC_SUBST([LIBBSD_ABI])
@@ -48,13 +48,50 @@ AM_CONDITIONAL([HAVE_LINKER_VERSION_SCRIPT],
# Checks for programs. # Checks for programs.
AC_PROG_CC AC_PROG_CC
AC_PROG_SED
AC_PROG_INSTALL AC_PROG_INSTALL
AC_PROG_LN_S AC_PROG_LN_S
# Set default compiler variables # Set default compiler variables
if test "$user_CFLAGS" = unset && test "$GCC" = yes; then AS_IF([test "$user_CFLAGS" = unset], [
CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter" LIBBSD_CHECK_COMPILER_FLAG([-Wall])
fi LIBBSD_CHECK_COMPILER_FLAG([-Wextra])
LIBBSD_CHECK_COMPILER_FLAG([-Wbad-function-cast])
LIBBSD_CHECK_COMPILER_FLAG([-Wc99-c11-compat])
LIBBSD_CHECK_COMPILER_FLAG([-Wcast-align])
LIBBSD_CHECK_COMPILER_FLAG([-Wdeclaration-after-statement])
LIBBSD_CHECK_COMPILER_FLAG([-Wdocumentation])
LIBBSD_CHECK_COMPILER_FLAG([-Wduplicated-branches])
LIBBSD_CHECK_COMPILER_FLAG([-Wduplicated-cond])
LIBBSD_CHECK_COMPILER_FLAG([-Wformat -Wformat-security])
LIBBSD_CHECK_COMPILER_FLAG([-Wformat=2])
LIBBSD_CHECK_COMPILER_FLAG([-Winit-self])
LIBBSD_CHECK_COMPILER_FLAG([-Wlogical-not-parentheses])
LIBBSD_CHECK_COMPILER_FLAG([-Wlogical-op])
LIBBSD_CHECK_COMPILER_FLAG([-Wmissing-declarations])
LIBBSD_CHECK_COMPILER_FLAG([-Wmissing-format-attribute])
LIBBSD_CHECK_COMPILER_FLAG([-Wmissing-prototypes])
LIBBSD_CHECK_COMPILER_FLAG([-Wnested-externs])
LIBBSD_CHECK_COMPILER_FLAG([-Wno-missing-field-initializers])
LIBBSD_CHECK_COMPILER_FLAG([-Wno-nonnull-compare])
LIBBSD_CHECK_COMPILER_FLAG([-Wno-tautological-constant-out-of-range-compare])
LIBBSD_CHECK_COMPILER_FLAG([-Wno-unused-parameter])
LIBBSD_CHECK_COMPILER_FLAG([-Wnull-dereference])
LIBBSD_CHECK_COMPILER_FLAG([-Wold-style-definition])
LIBBSD_CHECK_COMPILER_FLAG([-Wpointer-arith])
LIBBSD_CHECK_COMPILER_FLAG([-Wregister])
LIBBSD_CHECK_COMPILER_FLAG([-Wrestrict])
LIBBSD_CHECK_COMPILER_FLAG([-Wshadow])
LIBBSD_CHECK_COMPILER_FLAG([-Wshift-negative-value])
LIBBSD_CHECK_COMPILER_FLAG([-Wsizeof-array-argument])
LIBBSD_CHECK_COMPILER_FLAG([-Wstrict-prototypes])
LIBBSD_CHECK_COMPILER_FLAG([-Wswitch-bool])
LIBBSD_CHECK_COMPILER_FLAG([-Wvla])
LIBBSD_CHECK_COMPILER_FLAG([-Wwrite-strings])
CFLAGS="$CFLAGS $LIBBSD_COMPILER_FLAGS"
])
# Checks for libraries. # Checks for libraries.
AC_CHECK_LIB([testu01], [unif01_CreateExternGenBits], AC_CHECK_LIB([testu01], [unif01_CreateExternGenBits],
@@ -65,15 +102,25 @@ AM_CONDITIONAL([HAVE_LIBTESTU01],
saved_LIBS="$LIBS" saved_LIBS="$LIBS"
AC_SEARCH_LIBS([MD5Update], [md], [ AC_SEARCH_LIBS([MD5Update], [md], [
AC_SEARCH_LIBS([SHA512Update], [md], [ AS_IF([test "x$ac_cv_search_MD5Update" != "xnone required"], [
MD_LIBS="-lmd" MD5_LIBS="$MD5_LIBS $ac_cv_search_MD5Update"
need_transparent_libmd=yes
]) ])
], [ ], [
AC_MSG_ERROR([cannot find required message digest functions in libc or libmd]) AC_MSG_ERROR([cannot find required MD5 functions in libc or libmd])
])
AC_SEARCH_LIBS([SHA512Update], [md], [
AS_IF([test "x$ac_cv_search_SHA512Update" != "xnone required"], [
LIBBSD_LIBS="$LIBBSD_LIBS $ac_cv_search_SHA512Update"
])
], [
AC_MSG_ERROR([cannot find required SHA-2 functions in libc or libmd])
]) ])
AC_SUBST([MD_LIBS])
LIBS="$saved_LIBS" LIBS="$saved_LIBS"
AM_CONDITIONAL([NEED_TRANSPARENT_LIBMD],
[test "x$need_transparent_libmd" = "xyes"])
is_windows=no is_windows=no
AS_CASE([$host_os], AS_CASE([$host_os],
[*-gnu*], [ [*-gnu*], [
@@ -81,10 +128,9 @@ AS_CASE([$host_os],
saved_LIBS="$LIBS" saved_LIBS="$LIBS"
AC_SEARCH_LIBS([clock_gettime], [rt], [ AC_SEARCH_LIBS([clock_gettime], [rt], [
AS_IF([test "x$ac_cv_search_clock_gettime" != "xnone required"], [ AS_IF([test "x$ac_cv_search_clock_gettime" != "xnone required"], [
CLOCK_GETTIME_LIBS="$ac_cv_search_clock_gettime" LIBBSD_LIBS="$LIBBSD_LIBS $ac_cv_search_clock_gettime"
]) ])
]) ])
AC_SUBST([CLOCK_GETTIME_LIBS])
LIBS="$saved_LIBS" LIBS="$saved_LIBS"
], ],
[*-musl*], [ [*-musl*], [
@@ -126,7 +172,7 @@ AC_CACHE_CHECK(
[[ [[
static int rc = 1; static int rc = 1;
static void init(int argc) { if (argc == 1) rc = 0; } static void init(int argc) { if (argc == 1) rc = 0; }
void (*init_func)(int argc) __attribute__((__section__(".init_array"))) = init; void (*init_func)(int argc) __attribute__((__section__(".init_array"), __used__)) = init;
int main() { return rc; } int main() { return rc; }
]] ]]
)], )],
@@ -192,8 +238,7 @@ AC_LINK_IFELSE(
[AC_DEFINE([HAVE___REGISTER_ATFORK], [1], [AC_DEFINE([HAVE___REGISTER_ATFORK], [1],
[Define to 1 if you have __register_atfork]) [Define to 1 if you have __register_atfork])
AC_MSG_RESULT([yes])], AC_MSG_RESULT([yes])],
[ARC4RANDOM_ATFORK_LIBS="-pthread" [LIBBSD_LIBS="$LIBBSD_LIBS -pthread"
AC_SUBST([ARC4RANDOM_ATFORK_LIBS])
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
]) ])
@@ -202,6 +247,9 @@ AC_CHECK_FUNCS([clearenv dirfd fopencookie __fpurge \
pstat_getproc sysconf]) pstat_getproc sysconf])
AM_CONDITIONAL([HAVE_GETENTROPY], [test "x$ac_cv_func_getentropy" = "xtrue"]) AM_CONDITIONAL([HAVE_GETENTROPY], [test "x$ac_cv_func_getentropy" = "xtrue"])
AC_SUBST([MD5_LIBS])
AC_SUBST([LIBBSD_LIBS])
AC_CONFIG_FILES([ AC_CONFIG_FILES([
Makefile Makefile
include/Makefile include/Makefile

View File

@@ -187,10 +187,10 @@
# else # else
# ifndef __cplusplus # ifndef __cplusplus
# define __offsetof(type, field) \ # define __offsetof(type, field) \
((__size_t)(__uintptr_t)((const volatile void *)&((type *)0)->field)) ((size_t)(uintptr_t)((const volatile void *)&((type *)0)->field))
# else # else
# define __offsetof(type, field) \ # define __offsetof(type, field) \
(__offsetof__ (reinterpret_cast <__size_t> \ (__offsetof__ (reinterpret_cast <size_t> \
(&reinterpret_cast <const volatile char &> \ (&reinterpret_cast <const volatile char &> \
(static_cast<type *> (0)->field)))) (static_cast<type *> (0)->field))))
# endif # endif
@@ -243,15 +243,15 @@
#endif #endif
#ifndef __DECONST #ifndef __DECONST
#define __DECONST(type, var) ((type)(__uintptr_t)(const void *)(var)) #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
#endif #endif
#ifndef __DEVOLATILE #ifndef __DEVOLATILE
#define __DEVOLATILE(type, var) ((type)(__uintptr_t)(volatile void *)(var)) #define __DEVOLATILE(type, var) ((type)(uintptr_t)(volatile void *)(var))
#endif #endif
#ifndef __DEQUALIFY #ifndef __DEQUALIFY
#define __DEQUALIFY(type, var) ((type)(__uintptr_t)(const volatile void *)(var)) #define __DEQUALIFY(type, var) ((type)(uintptr_t)(const volatile void *)(var))
#endif #endif
#endif #endif

View File

@@ -1,4 +1,6 @@
/*- /*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993 * Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
* *
@@ -10,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors * 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 * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
@@ -80,17 +82,25 @@
* *
* For details on the use of these macros, see the queue(3) manual page. * For details on the use of these macros, see the queue(3) manual page.
* *
* Below is a summary of implemented functions where:
* + means the macro is available
* - means the macro is not available
* s means the macro is available but is slow (runs in O(n) time)
* *
* SLIST LIST STAILQ TAILQ * SLIST LIST STAILQ TAILQ
* _HEAD + + + + * _HEAD + + + +
* _CLASS_HEAD + + + +
* _HEAD_INITIALIZER + + + + * _HEAD_INITIALIZER + + + +
* _ENTRY + + + + * _ENTRY + + + +
* _CLASS_ENTRY + + + +
* _INIT + + + + * _INIT + + + +
* _EMPTY + + + + * _EMPTY + + + +
* _END + + + +
* _FIRST + + + + * _FIRST + + + +
* _NEXT + + + + * _NEXT + + + +
* _PREV - + - + * _PREV - + - +
* _LAST - - + + * _LAST - - + +
* _LAST_FAST - - - +
* _FOREACH + + + + * _FOREACH + + + +
* _FOREACH_FROM + + + + * _FOREACH_FROM + + + +
* _FOREACH_SAFE + + + + * _FOREACH_SAFE + + + +
@@ -103,14 +113,20 @@
* _INSERT_BEFORE - + - + * _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + + * _INSERT_AFTER + + + +
* _INSERT_TAIL - - + + * _INSERT_TAIL - - + +
* _CONCAT - - + + * _CONCAT s s + +
* _REMOVE_AFTER + - + - * _REMOVE_AFTER + - + -
* _REMOVE_HEAD + - + - * _REMOVE_HEAD + - + -
* _REMOVE + + + + * _REMOVE s + s +
* _SWAP + + + + * _SWAP + + + +
* *
*/ */
#ifdef QUEUE_MACRO_DEBUG #ifdef QUEUE_MACRO_DEBUG
#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH
#define QUEUE_MACRO_DEBUG_TRACE
#define QUEUE_MACRO_DEBUG_TRASH
#endif
#ifdef QUEUE_MACRO_DEBUG_TRACE
/* Store the last 2 places the queue element or head was altered */ /* Store the last 2 places the queue element or head was altered */
struct qm_trace { struct qm_trace {
unsigned long lastline; unsigned long lastline;
@@ -120,9 +136,7 @@ struct qm_trace {
}; };
#define TRACEBUF struct qm_trace trace; #define TRACEBUF struct qm_trace trace;
#define TRACEBUF_INITIALIZER { __FILE__, __LINE__, NULL, 0 } , #define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } ,
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define QMD_TRACE_HEAD(head) do { \ #define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \ (head)->trace.prevline = (head)->trace.lastline; \
@@ -138,14 +152,31 @@ struct qm_trace {
(elem)->trace.lastfile = __FILE__; \ (elem)->trace.lastfile = __FILE__; \
} while (0) } while (0)
#else #else /* !QUEUE_MACRO_DEBUG_TRACE */
#define QMD_TRACE_ELEM(elem) #define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head) #define QMD_TRACE_HEAD(head)
#define QMD_SAVELINK(name, link)
#define TRACEBUF #define TRACEBUF
#define TRACEBUF_INITIALIZER #define TRACEBUF_INITIALIZER
#endif /* QUEUE_MACRO_DEBUG_TRACE */
#ifdef QUEUE_MACRO_DEBUG_TRASH
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_IS_TRASHED(x) ((x) == (void *)(intptr_t)-1)
#else /* !QUEUE_MACRO_DEBUG_TRASH */
#define QMD_SAVELINK(name, link)
#define TRASHIT(x) #define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */ #define QMD_IS_TRASHED(x) 0
#endif /* QUEUE_MACRO_DEBUG_TRASH */
#ifdef __cplusplus
/*
* In C++ there can be structure lists and class lists:
*/
#define QUEUE_TYPEOF(type) type
#else
#define QUEUE_TYPEOF(type) struct type
#endif
/* /*
* Singly-linked List declarations. * Singly-linked List declarations.
@@ -155,6 +186,11 @@ struct name { \
struct type *slh_first; /* first element */ \ struct type *slh_first; /* first element */ \
} }
#define SLIST_CLASS_HEAD(name, type) \
struct name { \
class type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \ #define SLIST_HEAD_INITIALIZER(head) \
{ NULL } { NULL }
@@ -163,9 +199,37 @@ struct { \
struct type *sle_next; /* next element */ \ struct type *sle_next; /* next element */ \
} }
#define SLIST_CLASS_ENTRY(type) \
struct { \
class type *sle_next; /* next element */ \
}
/* /*
* Singly-linked List functions. * Singly-linked List functions.
*/ */
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \
if (*(prevp) != (elm)) \
panic("Bad prevptr *(%p) == %p != %p", \
(prevp), *(prevp), (elm)); \
} while (0)
#else
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm)
#endif
#define SLIST_CONCAT(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \
if (curelm == NULL) { \
if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \
SLIST_INIT(head2); \
} else if (SLIST_FIRST(head2) != NULL) { \
while (SLIST_NEXT(curelm, field) != NULL) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_NEXT(curelm, field) = SLIST_FIRST(head2); \
SLIST_INIT(head2); \
} \
} while (0)
#define SLIST_EMPTY(head) ((head)->slh_first == NULL) #define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_FIRST(head) ((head)->slh_first)
@@ -217,7 +281,7 @@ struct { \
SLIST_REMOVE_HEAD((head), field); \ SLIST_REMOVE_HEAD((head), field); \
} \ } \
else { \ else { \
struct type *curelm = SLIST_FIRST((head)); \ QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \
while (SLIST_NEXT(curelm, field) != (elm)) \ while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \ curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \ SLIST_REMOVE_AFTER(curelm, field); \
@@ -234,12 +298,20 @@ struct { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0) } while (0)
#define SLIST_REMOVE_PREVPTR(prevp, elm, field) do { \
QMD_SLIST_CHECK_PREVPTR(prevp, elm); \
*(prevp) = SLIST_NEXT(elm, field); \
TRASHIT((elm)->field.sle_next); \
} while (0)
#define SLIST_SWAP(head1, head2, type) do { \ #define SLIST_SWAP(head1, head2, type) do { \
struct type *swap_first = SLIST_FIRST(head1); \ QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \
SLIST_FIRST(head1) = SLIST_FIRST(head2); \ SLIST_FIRST(head1) = SLIST_FIRST(head2); \
SLIST_FIRST(head2) = swap_first; \ SLIST_FIRST(head2) = swap_first; \
} while (0) } while (0)
#define SLIST_END(head) NULL
/* /*
* Singly-linked Tail queue declarations. * Singly-linked Tail queue declarations.
*/ */
@@ -249,6 +321,12 @@ struct name { \
struct type **stqh_last;/* addr of last next element */ \ struct type **stqh_last;/* addr of last next element */ \
} }
#define STAILQ_CLASS_HEAD(name, type) \
struct name { \
class type *stqh_first; /* first element */ \
class type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \ #define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first } { NULL, &(head).stqh_first }
@@ -257,6 +335,11 @@ struct { \
struct type *stqe_next; /* next element */ \ struct type *stqe_next; /* next element */ \
} }
#define STAILQ_CLASS_ENTRY(type) \
struct { \
class type *stqe_next; /* next element */ \
}
/* /*
* Singly-linked Tail queue functions. * Singly-linked Tail queue functions.
*/ */
@@ -315,9 +398,10 @@ struct { \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0) } while (0)
#define STAILQ_LAST(head, type, field) \ #define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? NULL : \ (STAILQ_EMPTY((head)) ? NULL : \
__containerof((head)->stqh_last, struct type, field.stqe_next)) __containerof((head)->stqh_last, \
QUEUE_TYPEOF(type), field.stqe_next))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
@@ -327,7 +411,7 @@ struct { \
STAILQ_REMOVE_HEAD((head), field); \ STAILQ_REMOVE_HEAD((head), field); \
} \ } \
else { \ else { \
struct type *curelm = STAILQ_FIRST((head)); \ QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \
while (STAILQ_NEXT(curelm, field) != (elm)) \ while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \ curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \ STAILQ_REMOVE_AFTER(head, curelm, field); \
@@ -348,8 +432,8 @@ struct { \
} while (0) } while (0)
#define STAILQ_SWAP(head1, head2, type) do { \ #define STAILQ_SWAP(head1, head2, type) do { \
struct type *swap_first = STAILQ_FIRST(head1); \ QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \
struct type **swap_last = (head1)->stqh_last; \ QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
(head1)->stqh_last = (head2)->stqh_last; \ (head1)->stqh_last = (head2)->stqh_last; \
STAILQ_FIRST(head2) = swap_first; \ STAILQ_FIRST(head2) = swap_first; \
@@ -360,6 +444,8 @@ struct { \
(head2)->stqh_last = &STAILQ_FIRST(head2); \ (head2)->stqh_last = &STAILQ_FIRST(head2); \
} while (0) } while (0)
#define STAILQ_END(head) NULL
/* /*
* List declarations. * List declarations.
@@ -369,6 +455,11 @@ struct name { \
struct type *lh_first; /* first element */ \ struct type *lh_first; /* first element */ \
} }
#define LIST_CLASS_HEAD(name, type) \
struct name { \
class type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \ #define LIST_HEAD_INITIALIZER(head) \
{ NULL } { NULL }
@@ -378,11 +469,23 @@ struct { \
struct type **le_prev; /* address of previous next element */ \ struct type **le_prev; /* address of previous next element */ \
} }
#define LIST_CLASS_ENTRY(type) \
struct { \
class type *le_next; /* next element */ \
class type **le_prev; /* address of previous next element */ \
}
/* /*
* List functions. * List functions.
*/ */
#if (defined(_KERNEL) && defined(INVARIANTS)) #if (defined(_KERNEL) && defined(INVARIANTS))
/*
* QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME)
*
* If the list is non-empty, validates that the first element of the list
* points back at 'head.'
*/
#define QMD_LIST_CHECK_HEAD(head, field) do { \ #define QMD_LIST_CHECK_HEAD(head, field) do { \
if (LIST_FIRST((head)) != NULL && \ if (LIST_FIRST((head)) != NULL && \
LIST_FIRST((head))->field.le_prev != \ LIST_FIRST((head))->field.le_prev != \
@@ -390,6 +493,12 @@ struct { \
panic("Bad list head %p first->prev != head", (head)); \ panic("Bad list head %p first->prev != head", (head)); \
} while (0) } while (0)
/*
* QMD_LIST_CHECK_NEXT(TYPE *elm, LIST_ENTRY NAME)
*
* If an element follows 'elm' in the list, validates that the next element
* points back at 'elm.'
*/
#define QMD_LIST_CHECK_NEXT(elm, field) do { \ #define QMD_LIST_CHECK_NEXT(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL && \ if (LIST_NEXT((elm), field) != NULL && \
LIST_NEXT((elm), field)->field.le_prev != \ LIST_NEXT((elm), field)->field.le_prev != \
@@ -397,6 +506,11 @@ struct { \
panic("Bad link elm %p next->prev != elm", (elm)); \ panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0) } while (0)
/*
* QMD_LIST_CHECK_PREV(TYPE *elm, LIST_ENTRY NAME)
*
* Validates that the previous element (or head of the list) points to 'elm.'
*/
#define QMD_LIST_CHECK_PREV(elm, field) do { \ #define QMD_LIST_CHECK_PREV(elm, field) do { \
if (*(elm)->field.le_prev != (elm)) \ if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \ panic("Bad link elm %p prev->next != elm", (elm)); \
@@ -407,6 +521,23 @@ struct { \
#define QMD_LIST_CHECK_PREV(elm, field) #define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */ #endif /* (_KERNEL && INVARIANTS) */
#define LIST_CONCAT(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \
if (curelm == NULL) { \
if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) { \
LIST_FIRST(head2)->field.le_prev = \
&LIST_FIRST((head1)); \
LIST_INIT(head2); \
} \
} else if (LIST_FIRST(head2) != NULL) { \
while (LIST_NEXT(curelm, field) != NULL) \
curelm = LIST_NEXT(curelm, field); \
LIST_NEXT(curelm, field) = LIST_FIRST(head2); \
LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field); \
LIST_INIT(head2); \
} \
} while (0)
#define LIST_EMPTY(head) ((head)->lh_first == NULL) #define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first) #define LIST_FIRST(head) ((head)->lh_first)
@@ -462,9 +593,10 @@ struct { \
#define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_PREV(elm, head, type, field) \ #define LIST_PREV(elm, head, type, field) \
((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
__containerof((elm)->field.le_prev, struct type, field.le_next)) __containerof((elm)->field.le_prev, \
QUEUE_TYPEOF(type), field.le_next))
#define LIST_REMOVE(elm, field) do { \ #define LIST_REMOVE(elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.le_next); \ QMD_SAVELINK(oldnext, (elm)->field.le_next); \
@@ -480,7 +612,7 @@ struct { \
} while (0) } while (0)
#define LIST_SWAP(head1, head2, type, field) do { \ #define LIST_SWAP(head1, head2, type, field) do { \
struct type *swap_tmp = LIST_FIRST((head1)); \ QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \ LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \ LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
@@ -489,6 +621,8 @@ struct { \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0) } while (0)
#define LIST_END(head) NULL
/* /*
* Tail queue declarations. * Tail queue declarations.
*/ */
@@ -499,6 +633,13 @@ struct name { \
TRACEBUF \ TRACEBUF \
} }
#define TAILQ_CLASS_HEAD(name, type) \
struct name { \
class type *tqh_first; /* first element */ \
class type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \ #define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first, TRACEBUF_INITIALIZER } { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
@@ -509,10 +650,23 @@ struct { \
TRACEBUF \ TRACEBUF \
} }
#define TAILQ_CLASS_ENTRY(type) \
struct { \
class type *tqe_next; /* next element */ \
class type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/* /*
* Tail queue functions. * Tail queue functions.
*/ */
#if (defined(_KERNEL) && defined(INVARIANTS)) #if (defined(_KERNEL) && defined(INVARIANTS))
/*
* QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
*
* If the tailq is non-empty, validates that the first element of the tailq
* points back at 'head.'
*/
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ #define QMD_TAILQ_CHECK_HEAD(head, field) do { \
if (!TAILQ_EMPTY(head) && \ if (!TAILQ_EMPTY(head) && \
TAILQ_FIRST((head))->field.tqe_prev != \ TAILQ_FIRST((head))->field.tqe_prev != \
@@ -520,11 +674,22 @@ struct { \
panic("Bad tailq head %p first->prev != head", (head)); \ panic("Bad tailq head %p first->prev != head", (head)); \
} while (0) } while (0)
/*
* QMD_TAILQ_CHECK_TAIL(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
*
* Validates that the tail of the tailq is a pointer to pointer to NULL.
*/
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ #define QMD_TAILQ_CHECK_TAIL(head, field) do { \
if (*(head)->tqh_last != NULL) \ if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0) } while (0)
/*
* QMD_TAILQ_CHECK_NEXT(TYPE *elm, TAILQ_ENTRY NAME)
*
* If an element follows 'elm' in the tailq, validates that the next element
* points back at 'elm.'
*/
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ #define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
if (TAILQ_NEXT((elm), field) != NULL && \ if (TAILQ_NEXT((elm), field) != NULL && \
TAILQ_NEXT((elm), field)->field.tqe_prev != \ TAILQ_NEXT((elm), field)->field.tqe_prev != \
@@ -532,6 +697,11 @@ struct { \
panic("Bad link elm %p next->prev != elm", (elm)); \ panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0) } while (0)
/*
* QMD_TAILQ_CHECK_PREV(TYPE *elm, TAILQ_ENTRY NAME)
*
* Validates that the previous element (or head of the tailq) points to 'elm.'
*/
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ #define QMD_TAILQ_CHECK_PREV(elm, field) do { \
if (*(elm)->field.tqe_prev != (elm)) \ if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \ panic("Bad link elm %p prev->next != elm", (elm)); \
@@ -616,7 +786,7 @@ struct { \
TAILQ_NEXT((listelm), field) = (elm); \ TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \ QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \ QMD_TRACE_ELEM(&(listelm)->field); \
} while (0) } while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
@@ -626,7 +796,7 @@ struct { \
*(listelm)->field.tqe_prev = (elm); \ *(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \ QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \ QMD_TRACE_ELEM(&(listelm)->field); \
} while (0) } while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \ #define TAILQ_INSERT_HEAD(head, elm, field) do { \
@@ -655,11 +825,25 @@ struct { \
#define TAILQ_LAST(head, headname) \ #define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last)) (*(((struct headname *)((head)->tqh_last))->tqh_last))
/*
* The FAST function is fast in that it causes no data access other
* then the access to the head. The standard LAST function above
* will cause a data access of both the element you want and
* the previous element. FAST is very useful for instances when
* you may want to prefetch the last data element.
*/
#define TAILQ_LAST_FAST(head, type, field) \
(TAILQ_EMPTY(head) ? NULL : __containerof((head)->tqh_last, QUEUE_TYPEOF(type), field.tqe_next))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \ #define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_PREV_FAST(elm, head, type, field) \
((elm)->field.tqe_prev == &(head)->tqh_first ? NULL : \
__containerof((elm)->field.tqe_prev, QUEUE_TYPEOF(type), field.tqe_next))
#define TAILQ_REMOVE(head, elm, field) do { \ #define TAILQ_REMOVE(head, elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
@@ -679,8 +863,8 @@ struct { \
} while (0) } while (0)
#define TAILQ_SWAP(head1, head2, type, field) do { \ #define TAILQ_SWAP(head1, head2, type, field) do { \
struct type *swap_first = (head1)->tqh_first; \ QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \
struct type **swap_last = (head1)->tqh_last; \ QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \
(head1)->tqh_first = (head2)->tqh_first; \ (head1)->tqh_first = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \ (head1)->tqh_last = (head2)->tqh_last; \
(head2)->tqh_first = swap_first; \ (head2)->tqh_first = swap_first; \
@@ -695,4 +879,6 @@ struct { \
(head2)->tqh_last = &(head2)->tqh_first; \ (head2)->tqh_last = &(head2)->tqh_first; \
} while (0) } while (0)
#define TAILQ_END(head) NULL
#endif /* !LIBBSD_SYS_QUEUE_H */ #endif /* !LIBBSD_SYS_QUEUE_H */

View File

@@ -99,8 +99,11 @@
* Provide both implementations and default for now on the historical one to * Provide both implementations and default for now on the historical one to
* avoid breakage, we will switch to the NetBSD one in libbsd 0.10.0 or so. * avoid breakage, we will switch to the NetBSD one in libbsd 0.10.0 or so.
* Define LIBBSD_NETBSD_VIS to switch to the NetBSD one now. * Define LIBBSD_NETBSD_VIS to switch to the NetBSD one now.
* Define LIBBSD_OPENBSD_VIS to keep using the OpenBSD one.
*/ */
#ifndef LIBBSD_NETBSD_VIS #if defined(LIBBSD_OPENBSD_VIS)
#undef LIBBSD_NETBSD_VIS
#elif !defined(LIBBSD_NETBSD_VIS)
#warning "NetBSD added incompatible strnvis() and strnunvis(), please see <bsd/vis.h> for more detils." #warning "NetBSD added incompatible strnvis() and strnunvis(), please see <bsd/vis.h> for more detils."
#endif #endif

2
m4/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.m4
!libbsd*.m4

24
m4/libbsd-compiler.m4 Normal file
View File

@@ -0,0 +1,24 @@
# Copyright © 2021 Guillem Jover <guillem@hadrons.org>
# LIBBSD_CHECK_COMPILER_FLAG
# -------------------------
AC_DEFUN([LIBBSD_CHECK_COMPILER_FLAG], [
AS_VAR_PUSHDEF([libbsd_varname_cache], [libbsd_cv_cflags_$1])
AC_CACHE_CHECK([whether $CC accepts $1], [libbsd_varname_cache], [
m4_define([libbsd_check_flag], m4_bpatsubst([$1], [^-Wno-], [-W]))
AS_VAR_COPY([libbsd_save_CFLAGS], [CFLAGS])
AS_VAR_SET([CFLAGS], ["-Werror libbsd_check_flag"])
AC_COMPILE_IFELSE([
AC_LANG_SOURCE([[]])
], [
AS_VAR_SET([libbsd_varname_cache], [yes])
], [
AS_VAR_SET([libbsd_varname_cache], [no])
])
AS_VAR_COPY([CFLAGS], [libbsd_save_CFLAGS])
])
AS_VAR_IF([libbsd_varname_cache], [yes], [
AS_VAR_APPEND([LIBBSD_COMPILER_FLAGS], [" $1"])
])
AS_VAR_POPDEF([libbsd_varname_cache])
])

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

1
man/LIST_CLASS_HEAD.3bsd Normal file
View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -11,9 +11,11 @@ CLEANFILES = \
SED_MD5_SUBST = -e 's/mdX/md5/g' -e 's/mdY/md4/g' -e 's/MDX/MD5/g' SED_MD5_SUBST = -e 's/mdX/md5/g' -e 's/mdY/md4/g' -e 's/MDX/MD5/g'
md5.3bsd: $(srcdir)/mdX.3bsd md5.3bsd: $(srcdir)/mdX.3bsd
$(AM_V_GEN) sed $(SED_MD5_SUBST) $< > $@ $(AM_V_GEN) $(SED) $(SED_MD5_SUBST) $< > $@
dist_man_MANS = \ dist_man_MANS = \
LIST_CLASS_ENTRY.3bsd \
LIST_CLASS_HEAD.3bsd \
LIST_EMPTY.3bsd \ LIST_EMPTY.3bsd \
LIST_ENTRY.3bsd \ LIST_ENTRY.3bsd \
LIST_FIRST.3bsd \ LIST_FIRST.3bsd \
@@ -54,6 +56,8 @@ dist_man_MANS = \
RB_REMOVE.3bsd \ RB_REMOVE.3bsd \
RB_RIGHT.3bsd \ RB_RIGHT.3bsd \
RB_ROOT.3bsd \ RB_ROOT.3bsd \
SLIST_CLASS_ENTRY.3bsd \
SLIST_CLASS_HEAD.3bsd \
SLIST_EMPTY.3bsd \ SLIST_EMPTY.3bsd \
SLIST_ENTRY.3bsd \ SLIST_ENTRY.3bsd \
SLIST_FIRST.3bsd \ SLIST_FIRST.3bsd \
@@ -70,6 +74,7 @@ dist_man_MANS = \
SLIST_REMOVE.3bsd \ SLIST_REMOVE.3bsd \
SLIST_REMOVE_AFTER.3bsd \ SLIST_REMOVE_AFTER.3bsd \
SLIST_REMOVE_HEAD.3bsd \ SLIST_REMOVE_HEAD.3bsd \
SLIST_REMOVE_PREVPTR.3bsd \
SLIST_SWAP.3bsd \ SLIST_SWAP.3bsd \
SPLAY_EMPTY.3bsd \ SPLAY_EMPTY.3bsd \
SPLAY_ENTRY.3bsd \ SPLAY_ENTRY.3bsd \
@@ -88,6 +93,8 @@ dist_man_MANS = \
SPLAY_REMOVE.3bsd \ SPLAY_REMOVE.3bsd \
SPLAY_RIGHT.3bsd \ SPLAY_RIGHT.3bsd \
SPLAY_ROOT.3bsd \ SPLAY_ROOT.3bsd \
STAILQ_CLASS_ENTRY.3bsd \
STAILQ_CLASS_HEAD.3bsd \
STAILQ_CONCAT.3bsd \ STAILQ_CONCAT.3bsd \
STAILQ_EMPTY.3bsd \ STAILQ_EMPTY.3bsd \
STAILQ_ENTRY.3bsd \ STAILQ_ENTRY.3bsd \
@@ -108,6 +115,8 @@ dist_man_MANS = \
STAILQ_REMOVE_AFTER.3bsd \ STAILQ_REMOVE_AFTER.3bsd \
STAILQ_REMOVE_HEAD.3bsd \ STAILQ_REMOVE_HEAD.3bsd \
STAILQ_SWAP.3bsd \ STAILQ_SWAP.3bsd \
TAILQ_CLASS_ENTRY.3bsd \
TAILQ_CLASS_HEAD.3bsd \
TAILQ_CONCAT.3bsd \ TAILQ_CONCAT.3bsd \
TAILQ_EMPTY.3bsd \ TAILQ_EMPTY.3bsd \
TAILQ_ENTRY.3bsd \ TAILQ_ENTRY.3bsd \

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -1,6 +1,6 @@
.\" libbsd man page .\" libbsd man page
.\" .\"
.\" Copyright © 2017-2018 Guillem Jover <guillem@hadrons.org> .\" Copyright © 2017-2021 Guillem Jover <guillem@hadrons.org>
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions .\" modification, are permitted provided that the following conditions
@@ -24,7 +24,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd May 21, 2018 .Dd Feb 13, 2021
.Dt LIBBSD 7 .Dt LIBBSD 7
.Os .Os
.Sh NAME .Sh NAME
@@ -42,7 +42,7 @@ The library can be used in an overlay mode, which is the preferred way, so
that the code is portable and requires no modification to the original BSD that the code is portable and requires no modification to the original BSD
code. code.
This can be done easily with the This can be done easily with the
.Xr pkg-config 3 .Xr pkg-config 1
library named library named
.Pa libbsd-overlay . .Pa libbsd-overlay .
Or by adding the system-specific include directory with the Or by adding the system-specific include directory with the
@@ -64,7 +64,7 @@ this is less portable as it makes using
mandatory and it will not work on BSD-based systems, and requires mandatory and it will not work on BSD-based systems, and requires
modifying original BSD code. modifying original BSD code.
This can be done with the This can be done with the
.Xr pkg-config 3 .Xr pkg-config 1
library named library named
.Pa libbsd . .Pa libbsd .
The includes in this case should be namespaced with The includes in this case should be namespaced with
@@ -73,13 +73,13 @@ such as
.In bsd/unistd.h . .In bsd/unistd.h .
.Pp .Pp
The package also provides a The package also provides a
.Pa bsd-ctor .Nm libbsd-ctor
static library that can be used to inject automatic constructors into a static library that can be used to inject automatic constructors into a
program so that the program so that the
.Fn setproctitle_init 3 .Fn setproctitle_init 3
function gets invoked automatically at startup time. function gets invoked automatically at startup time.
This can be done with the This can be done with the
.Xr pkg-config 3 .Xr pkg-config 1
library named library named
.Pa libbsd-ctor . .Pa libbsd-ctor .
.Sh HEADERS .Sh HEADERS
@@ -94,11 +94,13 @@ be prefixed with
.It In bitstring.h .It In bitstring.h
.It In err.h .It In err.h
.It In getopt.h .It In getopt.h
.It In grp.h
.It In inttypes.h .It In inttypes.h
.It In libutil.h .It In libutil.h
.It In md5.h .It In md5.h
.It In netinet/ip_icmp.h .It In netinet/ip_icmp.h
.It In nlist.h .It In nlist.h
.It In pwd.h
.It In readpassphrase.h .It In readpassphrase.h
.It In stdio.h .It In stdio.h
.It In stdlib.h .It In stdlib.h
@@ -107,6 +109,7 @@ be prefixed with
.It In sys/bitstring.h .It In sys/bitstring.h
.It In sys/cdefs.h .It In sys/cdefs.h
.It In sys/endian.h .It In sys/endian.h
.It In sys/param.h
.It In sys/poll.h .It In sys/poll.h
.It In sys/queue.h .It In sys/queue.h
.It In sys/time.h .It In sys/time.h
@@ -125,6 +128,46 @@ It only works in non-overlay mode.
.Bl -tag -width 4m -compact .Bl -tag -width 4m -compact
.It In bsd/bsd.h .It In bsd/bsd.h
.El .El
.Sh ALTERNATIVES
Some functions have different prototypes depending on the BSD where they
originated from, and these various implementations provided are selectable
at build-time.
.Pp
This is the list of functions that provide multiple implementations:
.Bl -tag -width 4m
.It Fn strnvis 3
.It Fn strnunvis 3
.Nx
added
.Fn strnvis 3
and
.Fn strnunvis 3
but unfortunately made it incompatible with the existing one in
.Ox
and Freedesktop's libbsd (the former having existed for over ten years).
Despite this incompatibility being reported during development (see
http://gnats.netbsd.org/44977) they still shipped it.
Even more unfortunately
.Fx
and later MacOS picked up this incompatible implementation.
.Pp
Provide both implementations and default for now to the historical one to
avoid breakage, but we will switch to the
.Nx
one in a later release, which is internally consistent with the other
.Xr vis 3
functions and is now more widespread.
Define
.Dv LIBBSD_NETBSD_VIS
to switch to the
.Nx
one now.
Define
.Dv LIBBSD_OPENBSD_VIS
to keep using the
.Ox
one.
.El
.Sh DEPRECATED .Sh DEPRECATED
Some functions have been deprecated, they will emit warnings at compile time Some functions have been deprecated, they will emit warnings at compile time
and possibly while being linked at run-time. and possibly while being linked at run-time.
@@ -216,6 +259,7 @@ This function is provided by
.Xr md5 3bsd , .Xr md5 3bsd ,
.Xr nlist 3bsd , .Xr nlist 3bsd ,
.Xr pidfile 3bsd , .Xr pidfile 3bsd ,
.Xr pwcache 3bsd ,
.Xr queue 3bsd , .Xr queue 3bsd ,
.Xr radixsort 3bsd , .Xr radixsort 3bsd ,
.Xr readpassphrase 3bsd , .Xr readpassphrase 3bsd ,

View File

@@ -28,35 +28,40 @@
.\" @(#)queue.3 8.2 (Berkeley) 1/24/94 .\" @(#)queue.3 8.2 (Berkeley) 1/24/94
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd June 17, 2013 .Dd September 8, 2016
.Dt QUEUE 3bsd .Dt QUEUE 3bsd
.Os .Os
.Sh NAME .Sh NAME
.Nm SLIST_CLASS_ENTRY ,
.Nm SLIST_CLASS_HEAD ,
.Nm SLIST_CONCAT ,
.Nm SLIST_EMPTY , .Nm SLIST_EMPTY ,
.Nm SLIST_ENTRY , .Nm SLIST_ENTRY ,
.Nm SLIST_FIRST , .Nm SLIST_FIRST ,
.Nm SLIST_FOREACH , .Nm SLIST_FOREACH ,
.Nm SLIST_FOREACH_FROM , .Nm SLIST_FOREACH_FROM ,
.Nm SLIST_FOREACH_SAFE ,
.Nm SLIST_FOREACH_FROM_SAFE , .Nm SLIST_FOREACH_FROM_SAFE ,
.Nm SLIST_FOREACH_SAFE ,
.Nm SLIST_HEAD , .Nm SLIST_HEAD ,
.Nm SLIST_HEAD_INITIALIZER , .Nm SLIST_HEAD_INITIALIZER ,
.Nm SLIST_INIT , .Nm SLIST_INIT ,
.Nm SLIST_INSERT_AFTER , .Nm SLIST_INSERT_AFTER ,
.Nm SLIST_INSERT_HEAD , .Nm SLIST_INSERT_HEAD ,
.Nm SLIST_NEXT , .Nm SLIST_NEXT ,
.Nm SLIST_REMOVE ,
.Nm SLIST_REMOVE_AFTER , .Nm SLIST_REMOVE_AFTER ,
.Nm SLIST_REMOVE_HEAD , .Nm SLIST_REMOVE_HEAD ,
.Nm SLIST_REMOVE ,
.Nm SLIST_SWAP , .Nm SLIST_SWAP ,
.Nm STAILQ_CLASS_ENTRY ,
.Nm STAILQ_CLASS_HEAD ,
.Nm STAILQ_CONCAT , .Nm STAILQ_CONCAT ,
.Nm STAILQ_EMPTY , .Nm STAILQ_EMPTY ,
.Nm STAILQ_ENTRY , .Nm STAILQ_ENTRY ,
.Nm STAILQ_FIRST , .Nm STAILQ_FIRST ,
.Nm STAILQ_FOREACH , .Nm STAILQ_FOREACH ,
.Nm STAILQ_FOREACH_FROM , .Nm STAILQ_FOREACH_FROM ,
.Nm STAILQ_FOREACH_SAFE ,
.Nm STAILQ_FOREACH_FROM_SAFE , .Nm STAILQ_FOREACH_FROM_SAFE ,
.Nm STAILQ_FOREACH_SAFE ,
.Nm STAILQ_HEAD , .Nm STAILQ_HEAD ,
.Nm STAILQ_HEAD_INITIALIZER , .Nm STAILQ_HEAD_INITIALIZER ,
.Nm STAILQ_INIT , .Nm STAILQ_INIT ,
@@ -65,17 +70,20 @@
.Nm STAILQ_INSERT_TAIL , .Nm STAILQ_INSERT_TAIL ,
.Nm STAILQ_LAST , .Nm STAILQ_LAST ,
.Nm STAILQ_NEXT , .Nm STAILQ_NEXT ,
.Nm STAILQ_REMOVE ,
.Nm STAILQ_REMOVE_AFTER , .Nm STAILQ_REMOVE_AFTER ,
.Nm STAILQ_REMOVE_HEAD , .Nm STAILQ_REMOVE_HEAD ,
.Nm STAILQ_REMOVE ,
.Nm STAILQ_SWAP , .Nm STAILQ_SWAP ,
.Nm LIST_CLASS_ENTRY ,
.Nm LIST_CLASS_HEAD ,
.Nm LIST_CONCAT ,
.Nm LIST_EMPTY , .Nm LIST_EMPTY ,
.Nm LIST_ENTRY , .Nm LIST_ENTRY ,
.Nm LIST_FIRST , .Nm LIST_FIRST ,
.Nm LIST_FOREACH , .Nm LIST_FOREACH ,
.Nm LIST_FOREACH_FROM , .Nm LIST_FOREACH_FROM ,
.Nm LIST_FOREACH_SAFE ,
.Nm LIST_FOREACH_FROM_SAFE , .Nm LIST_FOREACH_FROM_SAFE ,
.Nm LIST_FOREACH_SAFE ,
.Nm LIST_HEAD , .Nm LIST_HEAD ,
.Nm LIST_HEAD_INITIALIZER , .Nm LIST_HEAD_INITIALIZER ,
.Nm LIST_INIT , .Nm LIST_INIT ,
@@ -86,18 +94,20 @@
.Nm LIST_PREV , .Nm LIST_PREV ,
.Nm LIST_REMOVE , .Nm LIST_REMOVE ,
.Nm LIST_SWAP , .Nm LIST_SWAP ,
.Nm TAILQ_CLASS_ENTRY ,
.Nm TAILQ_CLASS_HEAD ,
.Nm TAILQ_CONCAT , .Nm TAILQ_CONCAT ,
.Nm TAILQ_EMPTY , .Nm TAILQ_EMPTY ,
.Nm TAILQ_ENTRY , .Nm TAILQ_ENTRY ,
.Nm TAILQ_FIRST , .Nm TAILQ_FIRST ,
.Nm TAILQ_FOREACH , .Nm TAILQ_FOREACH ,
.Nm TAILQ_FOREACH_FROM , .Nm TAILQ_FOREACH_FROM ,
.Nm TAILQ_FOREACH_SAFE ,
.Nm TAILQ_FOREACH_FROM_SAFE , .Nm TAILQ_FOREACH_FROM_SAFE ,
.Nm TAILQ_FOREACH_REVERSE , .Nm TAILQ_FOREACH_REVERSE ,
.Nm TAILQ_FOREACH_REVERSE_FROM , .Nm TAILQ_FOREACH_REVERSE_FROM ,
.Nm TAILQ_FOREACH_REVERSE_SAFE ,
.Nm TAILQ_FOREACH_REVERSE_FROM_SAFE , .Nm TAILQ_FOREACH_REVERSE_FROM_SAFE ,
.Nm TAILQ_FOREACH_REVERSE_SAFE ,
.Nm TAILQ_FOREACH_SAFE ,
.Nm TAILQ_HEAD , .Nm TAILQ_HEAD ,
.Nm TAILQ_HEAD_INITIALIZER , .Nm TAILQ_HEAD_INITIALIZER ,
.Nm TAILQ_INIT , .Nm TAILQ_INIT ,
@@ -122,52 +132,60 @@ lists and tail queues
.Xr libbsd 7 .Xr libbsd 7
for include usage.) for include usage.)
.\" .\"
.Fn SLIST_CLASS_ENTRY "CLASSTYPE"
.Fn SLIST_CLASS_HEAD "HEADNAME" "CLASSTYPE"
.Fn SLIST_CONCAT "SLIST_HEAD *head1" "SLIST_HEAD *head2" "TYPE" "SLIST_ENTRY NAME"
.Fn SLIST_EMPTY "SLIST_HEAD *head" .Fn SLIST_EMPTY "SLIST_HEAD *head"
.Fn SLIST_ENTRY "TYPE" .Fn SLIST_ENTRY "TYPE"
.Fn SLIST_FIRST "SLIST_HEAD *head" .Fn SLIST_FIRST "SLIST_HEAD *head"
.Fn SLIST_FOREACH "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" .Fn SLIST_FOREACH "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
.Fn SLIST_FOREACH_FROM "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" .Fn SLIST_FOREACH_FROM "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
.Fn SLIST_FOREACH_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
.Fn SLIST_FOREACH_FROM_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var" .Fn SLIST_FOREACH_FROM_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
.Fn SLIST_FOREACH_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
.Fn SLIST_HEAD "HEADNAME" "TYPE" .Fn SLIST_HEAD "HEADNAME" "TYPE"
.Fn SLIST_HEAD_INITIALIZER "SLIST_HEAD head" .Fn SLIST_HEAD_INITIALIZER "SLIST_HEAD head"
.Fn SLIST_INIT "SLIST_HEAD *head" .Fn SLIST_INIT "SLIST_HEAD *head"
.Fn SLIST_INSERT_AFTER "TYPE *listelm" "TYPE *elm" "SLIST_ENTRY NAME" .Fn SLIST_INSERT_AFTER "TYPE *listelm" "TYPE *elm" "SLIST_ENTRY NAME"
.Fn SLIST_INSERT_HEAD "SLIST_HEAD *head" "TYPE *elm" "SLIST_ENTRY NAME" .Fn SLIST_INSERT_HEAD "SLIST_HEAD *head" "TYPE *elm" "SLIST_ENTRY NAME"
.Fn SLIST_NEXT "TYPE *elm" "SLIST_ENTRY NAME" .Fn SLIST_NEXT "TYPE *elm" "SLIST_ENTRY NAME"
.Fn SLIST_REMOVE "SLIST_HEAD *head" "TYPE *elm" "TYPE" "SLIST_ENTRY NAME"
.Fn SLIST_REMOVE_AFTER "TYPE *elm" "SLIST_ENTRY NAME" .Fn SLIST_REMOVE_AFTER "TYPE *elm" "SLIST_ENTRY NAME"
.Fn SLIST_REMOVE_HEAD "SLIST_HEAD *head" "SLIST_ENTRY NAME" .Fn SLIST_REMOVE_HEAD "SLIST_HEAD *head" "SLIST_ENTRY NAME"
.Fn SLIST_REMOVE "SLIST_HEAD *head" "TYPE *elm" "TYPE" "SLIST_ENTRY NAME" .Fn SLIST_SWAP "SLIST_HEAD *head1" "SLIST_HEAD *head2" "TYPE"
.Fn SLIST_SWAP "SLIST_HEAD *head1" "SLIST_HEAD *head2" "SLIST_ENTRY NAME"
.\" .\"
.Fn STAILQ_CLASS_ENTRY "CLASSTYPE"
.Fn STAILQ_CLASS_HEAD "HEADNAME" "CLASSTYPE"
.Fn STAILQ_CONCAT "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" .Fn STAILQ_CONCAT "STAILQ_HEAD *head1" "STAILQ_HEAD *head2"
.Fn STAILQ_EMPTY "STAILQ_HEAD *head" .Fn STAILQ_EMPTY "STAILQ_HEAD *head"
.Fn STAILQ_ENTRY "TYPE" .Fn STAILQ_ENTRY "TYPE"
.Fn STAILQ_FIRST "STAILQ_HEAD *head" .Fn STAILQ_FIRST "STAILQ_HEAD *head"
.Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" .Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
.Fn STAILQ_FOREACH_FROM "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" .Fn STAILQ_FOREACH_FROM "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
.Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn STAILQ_FOREACH_FROM_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var" .Fn STAILQ_FOREACH_FROM_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn STAILQ_HEAD "HEADNAME" "TYPE" .Fn STAILQ_HEAD "HEADNAME" "TYPE"
.Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head" .Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head"
.Fn STAILQ_INIT "STAILQ_HEAD *head" .Fn STAILQ_INIT "STAILQ_HEAD *head"
.Fn STAILQ_INSERT_AFTER "STAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "STAILQ_ENTRY NAME" .Fn STAILQ_INSERT_AFTER "STAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_INSERT_HEAD "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" .Fn STAILQ_INSERT_HEAD "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_INSERT_TAIL "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" .Fn STAILQ_INSERT_TAIL "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE" "STAILQ_ENTRY NAME" .Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_NEXT "TYPE *elm" "STAILQ_ENTRY NAME" .Fn STAILQ_NEXT "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE "STAILQ_HEAD *head" "TYPE *elm" "TYPE" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE_AFTER "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" .Fn STAILQ_REMOVE_AFTER "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE_HEAD "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" .Fn STAILQ_REMOVE_HEAD "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE "STAILQ_HEAD *head" "TYPE *elm" "TYPE" "STAILQ_ENTRY NAME" .Fn STAILQ_SWAP "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" "TYPE"
.Fn STAILQ_SWAP "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" "STAILQ_ENTRY NAME"
.\" .\"
.Fn LIST_CLASS_ENTRY "CLASSTYPE"
.Fn LIST_CLASS_HEAD "HEADNAME" "CLASSTYPE"
.Fn LIST_CONCAT "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME"
.Fn LIST_EMPTY "LIST_HEAD *head" .Fn LIST_EMPTY "LIST_HEAD *head"
.Fn LIST_ENTRY "TYPE" .Fn LIST_ENTRY "TYPE"
.Fn LIST_FIRST "LIST_HEAD *head" .Fn LIST_FIRST "LIST_HEAD *head"
.Fn LIST_FOREACH "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" .Fn LIST_FOREACH "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
.Fn LIST_FOREACH_FROM "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" .Fn LIST_FOREACH_FROM "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
.Fn LIST_FOREACH_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
.Fn LIST_FOREACH_FROM_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var" .Fn LIST_FOREACH_FROM_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
.Fn LIST_FOREACH_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
.Fn LIST_HEAD "HEADNAME" "TYPE" .Fn LIST_HEAD "HEADNAME" "TYPE"
.Fn LIST_HEAD_INITIALIZER "LIST_HEAD head" .Fn LIST_HEAD_INITIALIZER "LIST_HEAD head"
.Fn LIST_INIT "LIST_HEAD *head" .Fn LIST_INIT "LIST_HEAD *head"
@@ -179,18 +197,20 @@ for include usage.)
.Fn LIST_REMOVE "TYPE *elm" "LIST_ENTRY NAME" .Fn LIST_REMOVE "TYPE *elm" "LIST_ENTRY NAME"
.Fn LIST_SWAP "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME" .Fn LIST_SWAP "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME"
.\" .\"
.Fn TAILQ_CLASS_ENTRY "CLASSTYPE"
.Fn TAILQ_CLASS_HEAD "HEADNAME" "CLASSTYPE"
.Fn TAILQ_CONCAT "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TAILQ_ENTRY NAME" .Fn TAILQ_CONCAT "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TAILQ_ENTRY NAME"
.Fn TAILQ_EMPTY "TAILQ_HEAD *head" .Fn TAILQ_EMPTY "TAILQ_HEAD *head"
.Fn TAILQ_ENTRY "TYPE" .Fn TAILQ_ENTRY "TYPE"
.Fn TAILQ_FIRST "TAILQ_HEAD *head" .Fn TAILQ_FIRST "TAILQ_HEAD *head"
.Fn TAILQ_FOREACH "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" .Fn TAILQ_FOREACH "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
.Fn TAILQ_FOREACH_FROM "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" .Fn TAILQ_FOREACH_FROM "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
.Fn TAILQ_FOREACH_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var" .Fn TAILQ_FOREACH_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_REVERSE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" .Fn TAILQ_FOREACH_REVERSE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
.Fn TAILQ_FOREACH_REVERSE_FROM "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" .Fn TAILQ_FOREACH_REVERSE_FROM "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
.Fn TAILQ_FOREACH_REVERSE_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_REVERSE_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var" .Fn TAILQ_FOREACH_REVERSE_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_REVERSE_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_HEAD "HEADNAME" "TYPE" .Fn TAILQ_HEAD "HEADNAME" "TYPE"
.Fn TAILQ_HEAD_INITIALIZER "TAILQ_HEAD head" .Fn TAILQ_HEAD_INITIALIZER "TAILQ_HEAD head"
.Fn TAILQ_INIT "TAILQ_HEAD *head" .Fn TAILQ_INIT "TAILQ_HEAD *head"
@@ -205,8 +225,18 @@ for include usage.)
.Fn TAILQ_SWAP "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TYPE" "TAILQ_ENTRY NAME" .Fn TAILQ_SWAP "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TYPE" "TAILQ_ENTRY NAME"
.\" .\"
.Sh DESCRIPTION .Sh DESCRIPTION
These macros define and operate on four types of data structures: These macros define and operate on four types of data structures which
singly-linked lists, singly-linked tail queues, lists, and tail queues. can be used in both C and C++ source code:
.Bl -enum -compact -offset indent
.It
Lists
.It
Singly-linked lists
.It
Singly-linked tail queues
.It
Tail queues
.El
All four structures support the following functionality: All four structures support the following functionality:
.Bl -enum -compact -offset indent .Bl -enum -compact -offset indent
.It .It
@@ -230,6 +260,8 @@ Singly-linked lists add the following functionality:
.Bl -enum -compact -offset indent .Bl -enum -compact -offset indent
.It .It
O(n) removal of any entry in the list. O(n) removal of any entry in the list.
.It
O(n) concatenation of two lists.
.El .El
.Pp .Pp
Singly-linked tail queues add the following functionality: Singly-linked tail queues add the following functionality:
@@ -277,6 +309,8 @@ Linked lists are the simplest of the doubly linked data structures.
They add the following functionality over the above: They add the following functionality over the above:
.Bl -enum -compact -offset indent .Bl -enum -compact -offset indent
.It .It
O(n) concatenation of two lists.
.It
They may be traversed backwards. They may be traversed backwards.
.El .El
However: However:
@@ -308,24 +342,39 @@ than singly-linked lists.
.Pp .Pp
In the macro definitions, In the macro definitions,
.Fa TYPE .Fa TYPE
is the name of a user defined structure, is the name of a user defined structure.
that must contain a field of type The structure must contain a field called
.Fa NAME
which is of type
.Li SLIST_ENTRY , .Li SLIST_ENTRY ,
.Li STAILQ_ENTRY , .Li STAILQ_ENTRY ,
.Li LIST_ENTRY , .Li LIST_ENTRY ,
or or
.Li TAILQ_ENTRY , .Li TAILQ_ENTRY .
named In the macro definitions,
.Fa NAME . .Fa CLASSTYPE
is the name of a user defined class.
The class must contain a field called
.Fa NAME
which is of type
.Li SLIST_CLASS_ENTRY ,
.Li STAILQ_CLASS_ENTRY ,
.Li LIST_CLASS_ENTRY ,
or
.Li TAILQ_CLASS_ENTRY .
The argument The argument
.Fa HEADNAME .Fa HEADNAME
is the name of a user defined structure that must be declared is the name of a user defined structure that must be declared
using the macros using the macros
.Li SLIST_HEAD , .Li SLIST_HEAD ,
.Li SLIST_CLASS_HEAD ,
.Li STAILQ_HEAD , .Li STAILQ_HEAD ,
.Li STAILQ_CLASS_HEAD ,
.Li LIST_HEAD , .Li LIST_HEAD ,
.Li LIST_CLASS_HEAD ,
.Li TAILQ_HEAD ,
or or
.Li TAILQ_HEAD . .Li TAILQ_CLASS_HEAD .
See the examples below for further explanation of how these See the examples below for further explanation of how these
macros are used. macros are used.
.Sh SINGLY-LINKED LISTS .Sh SINGLY-LINKED LISTS
@@ -367,6 +416,19 @@ evaluates to an initializer for the list
.Fa head . .Fa head .
.Pp .Pp
The macro The macro
.Nm SLIST_CONCAT
concatenates the list headed by
.Fa head2
onto the end of the one headed by
.Fa head1
removing all entries from the former.
Use of this macro should be avoided as it traverses the entirety of the
.Fa head1
list.
A singly-linked tail queue should be used if this macro is needed in
high-usage code paths or to operate on long lists.
.Pp
The macro
.Nm SLIST_EMPTY .Nm SLIST_EMPTY
evaluates to true if there are no elements in the list. evaluates to true if there are no elements in the list.
.Pp .Pp
@@ -474,6 +536,9 @@ The macro
removes the element removes the element
.Fa elm .Fa elm
from the list. from the list.
Use of this macro should be avoided as it traverses the entire list.
A doubly-linked list should be used if this macro is needed in
high-usage code paths or to operate on long lists.
.Pp .Pp
The macro The macro
.Nm SLIST_SWAP .Nm SLIST_SWAP
@@ -690,6 +755,9 @@ The macro
removes the element removes the element
.Fa elm .Fa elm
from the tail queue. from the tail queue.
Use of this macro should be avoided as it traverses the entire list.
A doubly-linked tail queue should be used if this macro is needed in
high-usage code paths or to operate on long tail queues.
.Pp .Pp
The macro The macro
.Nm STAILQ_SWAP .Nm STAILQ_SWAP
@@ -789,6 +857,19 @@ evaluates to an initializer for the list
.Fa head . .Fa head .
.Pp .Pp
The macro The macro
.Nm LIST_CONCAT
concatenates the list headed by
.Fa head2
onto the end of the one headed by
.Fa head1
removing all entries from the former.
Use of this macro should be avoided as it traverses the entirety of the
.Fa head1
list.
A tail queue should be used if this macro is needed in
high-usage code paths or to operate on long lists.
.Pp
The macro
.Nm LIST_EMPTY .Nm LIST_EMPTY
evaluates to true if there are no elements in the list. evaluates to true if there are no elements in the list.
.Pp .Pp
@@ -1210,6 +1291,26 @@ while (n1 != NULL) {
} }
TAILQ_INIT(&head); TAILQ_INIT(&head);
.Ed .Ed
.Sh DIAGNOSTICS
When debugging
.Nm queue(3) ,
it can be useful to trace queue changes.
To enable tracing, define the macro
.Va QUEUE_MACRO_DEBUG_TRACE
at compile time.
.Pp
It can also be useful to trash pointers that have been unlinked from a queue,
to detect use after removal.
To enable pointer trashing, define the macro
.Va QUEUE_MACRO_DEBUG_TRASH
at compile time.
The macro
.Fn QMD_IS_TRASHED "void *ptr"
returns true if
.Fa ptr
has been trashed by the
.Va QUEUE_MACRO_DEBUG_TRASH
option.
.Sh SEE ALSO .Sh SEE ALSO
.Xr tree 3bsd .Xr tree 3bsd
.Sh HISTORY .Sh HISTORY

View File

@@ -1,36 +1,29 @@
.\" $OpenBSD: tree.3,v 1.7 2002/06/12 01:09:20 provos Exp $ .\" $OpenBSD: tree.3,v 1.30 2019/05/10 13:13:14 florian Exp $
.\" .\"/*
.\" Copyright 2002 Niels Provos <provos@citi.umich.edu> .\" * Copyright 2002 Niels Provos <provos@citi.umich.edu>
.\" All rights reserved. .\" * All rights reserved.
.\" .\" *
.\" Redistribution and use in source and binary forms, with or without .\" * Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions .\" * modification, are permitted provided that the following conditions
.\" are met: .\" * are met:
.\" 1. Redistributions of source code must retain the above copyright .\" * 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer. .\" * notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright .\" * 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the .\" * notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution. .\" * documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software .\" *
.\" must display the following acknowledgement: .\" * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" This product includes software developed by Niels Provos. .\" * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" 4. The name of the author may not be used to endorse or promote products .\" * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" derived from this software without specific prior written permission. .\" * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" .\" * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" */
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .Dd May 10, 2019
.\" 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.
.\"
.\" $FreeBSD$
.\"
.Dd December 27, 2007
.Dt TREE 3bsd .Dt TREE 3bsd
.Os .Os
.Sh NAME .Sh NAME
@@ -70,7 +63,9 @@
.Nm RB_RIGHT , .Nm RB_RIGHT ,
.Nm RB_PARENT , .Nm RB_PARENT ,
.Nm RB_FOREACH , .Nm RB_FOREACH ,
.Nm RB_FOREACH_SAFE ,
.Nm RB_FOREACH_REVERSE , .Nm RB_FOREACH_REVERSE ,
.Nm RB_FOREACH_REVERSE_SAFE ,
.Nm RB_INIT , .Nm RB_INIT ,
.Nm RB_INSERT , .Nm RB_INSERT ,
.Nm RB_REMOVE .Nm RB_REMOVE
@@ -84,88 +79,92 @@
(See (See
.Xr libbsd 7 .Xr libbsd 7
for include usage.) for include usage.)
.Fn SPLAY_PROTOTYPE NAME TYPE FIELD CMP .Pp
.Fn SPLAY_GENERATE NAME TYPE FIELD CMP .Fn SPLAY_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP"
.Fn SPLAY_ENTRY TYPE .Fn SPLAY_GENERATE "NAME" "TYPE" "FIELD" "CMP"
.Fn SPLAY_HEAD HEADNAME TYPE .Fn SPLAY_ENTRY "TYPE"
.Fn SPLAY_HEAD "HEADNAME" "TYPE"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn SPLAY_INITIALIZER "SPLAY_HEAD *head" .Fn SPLAY_INITIALIZER "SPLAY_HEAD *head"
.Fn SPLAY_ROOT "SPLAY_HEAD *head" .Fn SPLAY_ROOT "SPLAY_HEAD *head"
.Ft bool .Ft "int"
.Fn SPLAY_EMPTY "SPLAY_HEAD *head" .Fn SPLAY_EMPTY "SPLAY_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn SPLAY_NEXT NAME "SPLAY_HEAD *head" "struct TYPE *elm" .Fn SPLAY_NEXT "NAME" "SPLAY_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn SPLAY_MIN NAME "SPLAY_HEAD *head" .Fn SPLAY_MIN "NAME" "SPLAY_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn SPLAY_MAX NAME "SPLAY_HEAD *head" .Fn SPLAY_MAX "NAME" "SPLAY_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn SPLAY_FIND NAME "SPLAY_HEAD *head" "struct TYPE *elm" .Fn SPLAY_FIND "NAME" "SPLAY_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn SPLAY_LEFT "struct TYPE *elm" "SPLAY_ENTRY NAME" .Fn SPLAY_LEFT "struct TYPE *elm" "SPLAY_ENTRY NAME"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn SPLAY_RIGHT "struct TYPE *elm" "SPLAY_ENTRY NAME" .Fn SPLAY_RIGHT "struct TYPE *elm" "SPLAY_ENTRY NAME"
.Fn SPLAY_FOREACH VARNAME NAME "SPLAY_HEAD *head" .Fn SPLAY_FOREACH "VARNAME" "NAME" "SPLAY_HEAD *head"
.Ft void .Ft void
.Fn SPLAY_INIT "SPLAY_HEAD *head" .Fn SPLAY_INIT "SPLAY_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn SPLAY_INSERT NAME "SPLAY_HEAD *head" "struct TYPE *elm" .Fn SPLAY_INSERT "NAME" "SPLAY_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn SPLAY_REMOVE NAME "SPLAY_HEAD *head" "struct TYPE *elm" .Fn SPLAY_REMOVE "NAME" "SPLAY_HEAD *head" "struct TYPE *elm"
.Fn RB_PROTOTYPE NAME TYPE FIELD CMP .Pp
.Fn RB_PROTOTYPE_STATIC NAME TYPE FIELD CMP .Fn RB_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP"
.Fn RB_GENERATE NAME TYPE FIELD CMP .Fn RB_PROTOTYPE_STATIC "NAME" "TYPE" "FIELD" "CMP"
.Fn RB_GENERATE_STATIC NAME TYPE FIELD CMP .Fn RB_GENERATE "NAME" "TYPE" "FIELD" "CMP"
.Fn RB_ENTRY TYPE .Fn RB_GENERATE_STATIC "NAME" "TYPE" "FIELD" "CMP"
.Fn RB_HEAD HEADNAME TYPE .Fn RB_ENTRY "TYPE"
.Fn RB_HEAD "HEADNAME" "TYPE"
.Fn RB_INITIALIZER "RB_HEAD *head" .Fn RB_INITIALIZER "RB_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_ROOT "RB_HEAD *head" .Fn RB_ROOT "RB_HEAD *head"
.Ft "bool" .Ft "int"
.Fn RB_EMPTY "RB_HEAD *head" .Fn RB_EMPTY "RB_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_NEXT NAME "RB_HEAD *head" "struct TYPE *elm" .Fn RB_NEXT "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_PREV NAME "RB_HEAD *head" "struct TYPE *elm" .Fn RB_PREV "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_MIN NAME "RB_HEAD *head" .Fn RB_MIN "NAME" "RB_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_MAX NAME "RB_HEAD *head" .Fn RB_MAX "NAME" "RB_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_FIND NAME "RB_HEAD *head" "struct TYPE *elm" .Fn RB_FIND "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_NFIND NAME "RB_HEAD *head" "struct TYPE *elm" .Fn RB_NFIND "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_LEFT "struct TYPE *elm" "RB_ENTRY NAME" .Fn RB_LEFT "struct TYPE *elm" "RB_ENTRY NAME"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_RIGHT "struct TYPE *elm" "RB_ENTRY NAME" .Fn RB_RIGHT "struct TYPE *elm" "RB_ENTRY NAME"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_PARENT "struct TYPE *elm" "RB_ENTRY NAME" .Fn RB_PARENT "struct TYPE *elm" "RB_ENTRY NAME"
.Fn RB_FOREACH VARNAME NAME "RB_HEAD *head" .Fn RB_FOREACH "VARNAME" "NAME" "RB_HEAD *head"
.Fn RB_FOREACH_REVERSE VARNAME NAME "RB_HEAD *head" .Fn RB_FOREACH_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
.Fn RB_FOREACH_REVERSE "VARNAME" "NAME" "RB_HEAD *head"
.Fn RB_FOREACH_REVERSE_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
.Ft void .Ft void
.Fn RB_INIT "RB_HEAD *head" .Fn RB_INIT "RB_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_INSERT NAME "RB_HEAD *head" "struct TYPE *elm" .Fn RB_INSERT "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_REMOVE NAME "RB_HEAD *head" "struct TYPE *elm" .Fn RB_REMOVE "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Sh DESCRIPTION .Sh DESCRIPTION
These macros define data structures for different types of trees: These macros define data structures for different types of trees:
splay trees and red-black trees. splay trees and red-black trees.
.Pp .Pp
In the macro definitions, In the macro definitions,
.Fa TYPE .Fa TYPE
is the name tag of a user defined structure that must contain a field of type is the name tag of a user defined structure that must contain a field named
.Vt SPLAY_ENTRY , .Fa FIELD ,
of type
.Li SPLAY_ENTRY
or or
.Vt RB_ENTRY , .Li RB_ENTRY .
named
.Fa ENTRYNAME .
The argument The argument
.Fa HEADNAME .Fa HEADNAME
is the name tag of a user defined structure that must be declared is the name tag of a user defined structure that must be declared
using the macros using the macros
.Fn SPLAY_HEAD , .Fn SPLAY_HEAD
or or
.Fn RB_HEAD . .Fn RB_HEAD .
The argument The argument
@@ -173,46 +172,38 @@ The argument
has to be a unique name prefix for every tree that is defined. has to be a unique name prefix for every tree that is defined.
.Pp .Pp
The function prototypes are declared with The function prototypes are declared with
.Fn SPLAY_PROTOTYPE , .Li SPLAY_PROTOTYPE ,
.Fn RB_PROTOTYPE , .Li RB_PROTOTYPE ,
or or
.Fn RB_PROTOTYPE_STATIC . .Li RB_PROTOTYPE_STATIC .
The function bodies are generated with The function bodies are generated with
.Fn SPLAY_GENERATE , .Li SPLAY_GENERATE ,
.Fn RB_GENERATE , .Li RB_GENERATE ,
or or
.Fn RB_GENERATE_STATIC . .Li RB_GENERATE_STATIC .
See the examples below for further explanation of how these macros are used. See the examples below for further explanation of how these macros are used.
.Sh SPLAY TREES .Sh SPLAY TREES
A splay tree is a self-organizing data structure. A splay tree is a self-organizing data structure.
Every operation on the tree causes a splay to happen. Every operation on the tree causes a splay to happen.
The splay moves the requested The splay moves the requested node to the root of the tree and partly
node to the root of the tree and partly rebalances it. rebalances it.
.Pp .Pp
This has the benefit that request locality causes faster lookups as This has the benefit that request locality causes faster lookups as
the requested nodes move to the top of the tree. the requested nodes move to the top of the tree.
On the other hand, every lookup causes memory writes. On the other hand, every lookup causes memory writes.
.Pp .Pp
The Balance Theorem bounds the total access time for The Balance Theorem bounds the total access time for m operations
.Ar m and n inserts on an initially empty tree as O((m + n)lg n).
operations and The amortized cost for a sequence of m accesses to a splay tree is O(lg n).
.Ar n
inserts on an initially empty tree as
.Fn O "\*[lp]m + n\*[rp]lg n" .
The
amortized cost for a sequence of
.Ar m
accesses to a splay tree is
.Fn O "lg n" .
.Pp .Pp
A splay tree is headed by a structure defined by the A splay tree is headed by a structure defined by the
.Fn SPLAY_HEAD .Fn SPLAY_HEAD
macro. macro.
A A
.Fa SPLAY_HEAD
structure is declared as follows: structure is declared as follows:
.Bd -ragged -offset indent .Bd -literal -offset indent
.Fn SPLAY_HEAD HEADNAME TYPE SPLAY_HEAD(HEADNAME, TYPE) head;
.Va head ;
.Ed .Ed
.Pp .Pp
where where
@@ -251,16 +242,15 @@ macro, but should be used only once.
Finally, Finally,
the the
.Fa CMP .Fa CMP
argument is the name of a function used to compare tree nodes argument is the name of a function used to compare trees' nodes
with each other. with each other.
The function takes two arguments of type The function takes two arguments of type
.Vt "struct TYPE *" . .Fa "struct TYPE *" .
If the first argument is smaller than the second, the function returns a If the first argument is smaller than the second, the function returns a
value smaller than zero. value smaller than zero.
If they are equal, the function returns zero. If they are equal, the function returns zero.
Otherwise, it should return a value greater than zero. Otherwise, it should return a value greater than zero.
The compare The compare function defines the order of the tree elements.
function defines the order of the tree elements.
.Pp .Pp
The The
.Fn SPLAY_INIT .Fn SPLAY_INIT
@@ -270,11 +260,8 @@ macro initializes the tree referenced by
The splay tree can also be initialized statically by using the The splay tree can also be initialized statically by using the
.Fn SPLAY_INITIALIZER .Fn SPLAY_INITIALIZER
macro like this: macro like this:
.Bd -ragged -offset indent .Bd -literal -offset indent
.Fn SPLAY_HEAD HEADNAME TYPE SPLAY_HEAD(HEADNAME, TYPE) head = SPLAY_INITIALIZER(&head);
.Va head
=
.Fn SPLAY_INITIALIZER &head ;
.Ed .Ed
.Pp .Pp
The The
@@ -282,6 +269,11 @@ The
macro inserts the new element macro inserts the new element
.Fa elm .Fa elm
into the tree. into the tree.
Upon success,
.Va NULL
is returned.
If a matching element already exists in the tree, the insertion is
aborted, and a pointer to the existing element is returned.
.Pp .Pp
The The
.Fn SPLAY_REMOVE .Fn SPLAY_REMOVE
@@ -289,6 +281,11 @@ macro removes the element
.Fa elm .Fa elm
from the tree pointed by from the tree pointed by
.Fa head . .Fa head .
Upon success, a pointer to the removed element is returned.
.Va NULL
is returned if
.Fa elm
is not present in the tree.
.Pp .Pp
The The
.Fn SPLAY_FIND .Fn SPLAY_FIND
@@ -296,7 +293,7 @@ macro can be used to find a particular element in the tree.
.Bd -literal -offset indent .Bd -literal -offset indent
struct TYPE find, *res; struct TYPE find, *res;
find.key = 30; find.key = 30;
res = SPLAY_FIND(NAME, head, &find); res = SPLAY_FIND(NAME, &head, &find);
.Ed .Ed
.Pp .Pp
The The
@@ -313,8 +310,8 @@ for (np = SPLAY_MIN(NAME, &head); np != NULL; np = SPLAY_NEXT(NAME, &head, np))
Or, for simplicity, one can use the Or, for simplicity, one can use the
.Fn SPLAY_FOREACH .Fn SPLAY_FOREACH
macro: macro:
.Bd -ragged -offset indent .Bd -literal -offset indent
.Fn SPLAY_FOREACH np NAME head SPLAY_FOREACH(np, NAME, &head)
.Ed .Ed
.Pp .Pp
The The
@@ -324,29 +321,28 @@ macro should be used to check whether a splay tree is empty.
A red-black tree is a binary search tree with the node color as an A red-black tree is a binary search tree with the node color as an
extra attribute. extra attribute.
It fulfills a set of conditions: It fulfills a set of conditions:
.Bl -enum -offset indent .Pp
.Bl -enum -compact -offset indent
.It .It
Every search path from the root to a leaf consists of the same number of every search path from the root to a leaf consists of the same number of
black nodes. black nodes,
.It .It
Each red node (except for the root) has a black parent. each red node (except for the root) has a black parent,
.It .It
Each leaf node is black. each leaf node is black.
.El .El
.Pp .Pp
Every operation on a red-black tree is bounded as Every operation on a red-black tree is bounded as O(lg n).
.Fn O "lg n" . The maximum height of a red-black tree is 2lg (n+1).
The maximum height of a red-black tree is
.Fn 2lg "n + 1" .
.Pp .Pp
A red-black tree is headed by a structure defined by the A red-black tree is headed by a structure defined by the
.Fn RB_HEAD .Fn RB_HEAD
macro. macro.
A A
.Fa RB_HEAD
structure is declared as follows: structure is declared as follows:
.Bd -ragged -offset indent .Bd -literal -offset indent
.Fn RB_HEAD HEADNAME TYPE RB_HEAD(HEADNAME, TYPE) head;
.Va head ;
.Ed .Ed
.Pp .Pp
where where
@@ -364,7 +360,7 @@ their prototypes need to be declared with the
.Fn RB_PROTOTYPE .Fn RB_PROTOTYPE
or or
.Fn RB_PROTOTYPE_STATIC .Fn RB_PROTOTYPE_STATIC
macro, macros,
where where
.Fa NAME .Fa NAME
is a unique identifier for this particular tree. is a unique identifier for this particular tree.
@@ -381,7 +377,7 @@ The function bodies are generated with the
.Fn RB_GENERATE .Fn RB_GENERATE
or or
.Fn RB_GENERATE_STATIC .Fn RB_GENERATE_STATIC
macro. macros.
These macros take the same arguments as the These macros take the same arguments as the
.Fn RB_PROTOTYPE .Fn RB_PROTOTYPE
and and
@@ -391,16 +387,15 @@ macros, but should be used only once.
Finally, Finally,
the the
.Fa CMP .Fa CMP
argument is the name of a function used to compare tree nodes argument is the name of a function used to compare trees' nodes
with each other. with each other.
The function takes two arguments of type The function takes two arguments of type
.Vt "struct TYPE *" . .Fa "struct TYPE *" .
If the first argument is smaller than the second, the function returns a If the first argument is smaller than the second, the function returns a
value smaller than zero. value smaller than zero.
If they are equal, the function returns zero. If they are equal, the function returns zero.
Otherwise, it should return a value greater than zero. Otherwise, it should return a value greater than zero.
The compare The compare function defines the order of the tree elements.
function defines the order of the tree elements.
.Pp .Pp
The The
.Fn RB_INIT .Fn RB_INIT
@@ -410,11 +405,8 @@ macro initializes the tree referenced by
The red-black tree can also be initialized statically by using the The red-black tree can also be initialized statically by using the
.Fn RB_INITIALIZER .Fn RB_INITIALIZER
macro like this: macro like this:
.Bd -ragged -offset indent .Bd -literal -offset indent
.Fn RB_HEAD HEADNAME TYPE RB_HEAD(HEADNAME, TYPE) head = RB_INITIALIZER(&head);
.Va head
=
.Fn RB_INITIALIZER &head ;
.Ed .Ed
.Pp .Pp
The The
@@ -422,6 +414,11 @@ The
macro inserts the new element macro inserts the new element
.Fa elm .Fa elm
into the tree. into the tree.
Upon success,
.Va NULL
is returned.
If a matching element already exists in the tree, the insertion is
aborted, and a pointer to the existing element is returned.
.Pp .Pp
The The
.Fn RB_REMOVE .Fn RB_REMOVE
@@ -429,16 +426,24 @@ macro removes the element
.Fa elm .Fa elm
from the tree pointed by from the tree pointed by
.Fa head . .Fa head .
.Fn RB_REMOVE
returns
.Fa elm .
.Pp .Pp
The The
.Fn RB_FIND .Fn RB_FIND
and and
.Fn RB_NFIND .Fn RB_NFIND
macros can be used to find a particular element in the tree. macros can be used to find a particular element in the tree.
.Fn RB_FIND
finds the node with the same key as
.Fa elm .
.Fn RB_NFIND
finds the first node greater than or equal to the search key.
.Bd -literal -offset indent .Bd -literal -offset indent
struct TYPE find, *res; struct TYPE find, *res;
find.key = 30; find.key = 30;
res = RB_FIND(NAME, head, &find); res = RB_FIND(NAME, &head, &find);
.Ed .Ed
.Pp .Pp
The The
@@ -449,26 +454,119 @@ The
and and
.Fn RB_PREV .Fn RB_PREV
macros can be used to traverse the tree: macros can be used to traverse the tree:
.Pp .Bd -literal -offset indent
.Dl "for (np = RB_MIN(NAME, &head); np != NULL; np = RB_NEXT(NAME, &head, np))" for (np = RB_MIN(NAME, &head); np != NULL; np = RB_NEXT(NAME, &head, np))
.Ed
.Pp .Pp
Or, for simplicity, one can use the Or, for simplicity, one can use the
.Fn RB_FOREACH .Fn RB_FOREACH
or or
.Fn RB_FOREACH_REVERSE .Fn RB_FOREACH_REVERSE
macro: macros:
.Bd -ragged -offset indent .Bd -literal -offset indent
.Fn RB_FOREACH np NAME head RB_FOREACH(np, NAME, &head)
.Ed .Ed
.Pp .Pp
The macros
.Fn RB_FOREACH_SAFE
and
.Fn RB_FOREACH_REVERSE_SAFE
traverse the tree referenced by head
in a forward or reverse direction respectively,
assigning each element in turn to np.
However, unlike their unsafe counterparts,
they permit both the removal of np
as well as freeing it from within the loop safely
without interfering with the traversal.
.Pp
The The
.Fn RB_EMPTY .Fn RB_EMPTY
macro should be used to check whether a red-black tree is empty. macro should be used to check whether a red-black tree is empty.
.Sh EXAMPLES
The following example demonstrates how to declare a red-black tree
holding integers.
Values are inserted into it and the contents of the tree are printed
in order.
Lastly, the internal structure of the tree is printed.
.Bd -literal -offset 3n
#include <sys/tree.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
struct node {
RB_ENTRY(node) entry;
int i;
};
int intcmp(struct node *, struct node *);
void print_tree(struct node *);
int
intcmp(struct node *e1, struct node *e2)
{
return (e1->i < e2->i ? -1 : e1->i > e2->i);
}
RB_HEAD(inttree, node) head = RB_INITIALIZER(&head);
RB_PROTOTYPE(inttree, node, entry, intcmp)
RB_GENERATE(inttree, node, entry, intcmp)
int testdata[] = {
20, 16, 17, 13, 3, 6, 1, 8, 2, 4, 10, 19, 5, 9, 12, 15, 18,
7, 11, 14
};
void
print_tree(struct node *n)
{
struct node *left, *right;
if (n == NULL) {
printf("nil");
return;
}
left = RB_LEFT(n, entry);
right = RB_RIGHT(n, entry);
if (left == NULL && right == NULL)
printf("%d", n->i);
else {
printf("%d(", n->i);
print_tree(left);
printf(",");
print_tree(right);
printf(")");
}
}
int
main(void)
{
int i;
struct node *n;
for (i = 0; i < sizeof(testdata) / sizeof(testdata[0]); i++) {
if ((n = malloc(sizeof(struct node))) == NULL)
err(1, NULL);
n->i = testdata[i];
RB_INSERT(inttree, &head, n);
}
RB_FOREACH(n, inttree, &head) {
printf("%d\en", n->i);
}
print_tree(RB_ROOT(&head));
printf("\en");
return (0);
}
.Ed
.Sh SEE ALSO
.Xr queue 3bsd
.Sh NOTES .Sh NOTES
Trying to free a tree in the following way is a common error: Trying to free a tree in the following way is a common error:
.Bd -literal -offset indent .Bd -literal -offset indent
SPLAY_FOREACH(var, NAME, head) { SPLAY_FOREACH(var, NAME, &head) {
SPLAY_REMOVE(NAME, head, var); SPLAY_REMOVE(NAME, &head, var);
free(var); free(var);
} }
free(head); free(head);
@@ -476,36 +574,17 @@ free(head);
.Pp .Pp
Since Since
.Va var .Va var
is freed, the is free'd, the
.Fn FOREACH .Fn FOREACH
macro refers to a pointer that may have been reallocated already. macro refers to a pointer that may have been reallocated already.
Proper code needs a second variable. Proper code needs a second variable.
.Bd -literal -offset indent .Bd -literal -offset indent
for (var = SPLAY_MIN(NAME, head); var != NULL; var = nxt) { for (var = SPLAY_MIN(NAME, &head); var != NULL; var = nxt) {
nxt = SPLAY_NEXT(NAME, head, var); nxt = SPLAY_NEXT(NAME, &head, var);
SPLAY_REMOVE(NAME, head, var); SPLAY_REMOVE(NAME, &head, var);
free(var); free(var);
} }
.Ed .Ed
.Pp
Both
.Fn RB_INSERT
and
.Fn SPLAY_INSERT
return
.Dv NULL
if the element was inserted in the tree successfully, otherwise they
return a pointer to the element with the colliding key.
.Pp
Accordingly,
.Fn RB_REMOVE
and
.Fn SPLAY_REMOVE
return the pointer to the removed element otherwise they return
.Dv NULL
to indicate an error.
.Sh SEE ALSO
.Xr queue 3bsd
.Sh AUTHORS .Sh AUTHORS
The author of the tree macros is The author of the tree macros is
.An Niels Provos . .An Niels Provos .

View File

@@ -25,6 +25,7 @@ libbsd_la_included_sources = \
getentropy_win.c \ getentropy_win.c \
$(nil) $(nil)
CLEANFILES =
EXTRA_DIST = \ EXTRA_DIST = \
libbsd.map \ libbsd.map \
libbsd.pc.in \ libbsd.pc.in \
@@ -52,9 +53,8 @@ libbsd_la_DEPENDENCIES = \
$(libbsd_la_included_sources) \ $(libbsd_la_included_sources) \
libbsd.map libbsd.map
libbsd_la_LIBADD = \ libbsd_la_LIBADD = \
$(MD_LIBS) \ $(MD5_LIBS) \
$(CLOCK_GETTIME_LIBS) \ $(LIBBSD_LIBS) \
$(ARC4RANDOM_ATFORK_LIBS) \
$(nil) $(nil)
libbsd_la_LDFLAGS = \ libbsd_la_LDFLAGS = \
-version-number $(LIBBSD_ABI) -version-number $(LIBBSD_ABI)
@@ -126,22 +126,51 @@ libbsd_la_SOURCES += \
$(nil) $(nil)
endif endif
if NEED_TRANSPARENT_LIBMD
CLEANFILES += \
format.ld \
# EOL
endif
libbsd_ctor_a_SOURCES = \ libbsd_ctor_a_SOURCES = \
setproctitle_ctor.c \ setproctitle_ctor.c \
$(nil) $(nil)
if NEED_TRANSPARENT_LIBMD
TRANSPARENT_LIBMD_DEPENDS = format.ld
format.ld:
$(CC) -shared -nostdlib -nostartfiles -x assembler /dev/null -o $@.so
objdump -f $@.so | sed -n 's/.*file format \(.*\)/OUTPUT_FORMAT(\1)/;T;p' > $@
rm -f $@.so
endif
runtimelibdir = $(libdir) runtimelibdir = $(libdir)
install-exec-hook: install-exec-hook: $(TRANSPARENT_LIBMD_DEPENDS)
if [ "$(libdir)" != "$(runtimelibdir)" ]; then \ if [ "$(libdir)" != "$(runtimelibdir)" ]; then \
$(MKDIR_P) $(DESTDIR)$(runtimelibdir); \ $(MKDIR_P) $(DESTDIR)$(runtimelibdir); \
mv $(DESTDIR)$(libdir)/libbsd*.so.* \ mv $(DESTDIR)$(libdir)/libbsd*.so.* \
$(DESTDIR)$(runtimelibdir)/; \ $(DESTDIR)$(runtimelibdir)/; \
fi
if NEED_TRANSPARENT_LIBMD
# The "GNU ld script" magic is required so that GNU ldconfig does not complain
# about an unknown format file.
soname=`readlink $(DESTDIR)$(libdir)/libbsd.so`; \
$(RM) $(DESTDIR)$(libdir)/libbsd.so; \
(echo '/* GNU ld script'; \
echo ' * The MD5 functions are provided by the libmd library. */'; \
cat format.ld; \
echo "GROUP($(runtimelibdir)/$$soname AS_NEEDED($(MD5_LIBS)))"; \
)>$(DESTDIR)$(libdir)/libbsd.so
else
if [ "$(libdir)" != "$(runtimelibdir)" ]; then \
soname=`readlink $(DESTDIR)$(libdir)/libbsd.so`; \ soname=`readlink $(DESTDIR)$(libdir)/libbsd.so`; \
sorelprefix=`echo $(libdir) | sed -r -e 's:(^/)?[^/]+:..:g'`; \ sorelprefix=`echo $(libdir) | $(SED) -r -e 's:(^/)?[^/]+:..:g'`; \
ln -sf $$sorelprefix$(runtimelibdir)/$$soname \ ln -sf $$sorelprefix$(runtimelibdir)/$$soname \
$(DESTDIR)$(libdir)/libbsd.so; \ $(DESTDIR)$(libdir)/libbsd.so; \
fi fi
endif
uninstall-hook: uninstall-hook:
rm -f $(DESTDIR)$(runtimelibdir)/libbsd*.so* rm -f $(DESTDIR)$(runtimelibdir)/libbsd*.so*

View File

@@ -1,6 +1,8 @@
/* /*
* Copyright (c) 2004-2005, 2007, 2010, 2012-2014 * SPDX-License-Identifier: ISC
* Todd C. Miller <Todd.Miller@courtesan.com> *
* Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -17,19 +19,17 @@
#include <config.h> #include <config.h>
#include <sys/types.h> #ifdef __linux__
#include <unistd.h> # include <sys/syscall.h>
#include <stdio.h> # if defined(__NR_close_range) && !defined(SYS_close_range)
#ifdef STDC_HEADERS # define SYS_close_range __NR_close_range
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif # endif
#endif /* STDC_HEADERS */ #endif
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HAVE_PSTAT_GETPROC #ifdef HAVE_PSTAT_GETPROC
# include <sys/param.h> # include <sys/param.h>
# include <sys/pstat.h> # include <sys/pstat.h>
@@ -56,10 +56,6 @@
# define OPEN_MAX 256 # define OPEN_MAX 256
#endif #endif
#if defined(HAVE_FCNTL_CLOSEM) && !defined(HAVE_DIRFD)
# define closefrom closefrom_fallback
#endif
static inline void static inline void
closefrom_close(int fd) closefrom_close(int fd)
{ {
@@ -71,56 +67,64 @@ closefrom_close(int fd)
#endif #endif
} }
#if defined(__linux__) && defined(SYS_close_range)
static inline int
sys_close_range(unsigned int fd, unsigned int max_fd, unsigned int flags)
{
return syscall(SYS_close_range, fd, max_fd, flags);
}
#endif
/* /*
* Close all file descriptors greater than or equal to lowfd. * Close all file descriptors greater than or equal to lowfd.
* This is the expensive (fallback) method. * This is the expensive (fallback) method.
*/ */
void static void
closefrom_fallback(int lowfd) closefrom_fallback(int lowfd)
{ {
long fd, maxfd; long fd, maxfd;
/* /*
* Fall back on sysconf() or getdtablesize(). We avoid checking * Fall back on sysconf(_SC_OPEN_MAX) or getdtablesize(). This is
* resource limits since it is possible to open a file descriptor * equivalent to checking the RLIMIT_NOFILE soft limit. It is
* and then drop the rlimit such that it is below the open fd. * possible for there to be open file descriptors past this limit
* but there is not much we can do about that since the hard limit
* may be RLIM_INFINITY (LLONG_MAX or ULLONG_MAX on modern systems).
*/ */
#ifdef HAVE_SYSCONF #ifdef HAVE_SYSCONF
maxfd = sysconf(_SC_OPEN_MAX); maxfd = sysconf(_SC_OPEN_MAX);
#else #else
maxfd = getdtablesize(); maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */ #endif /* HAVE_SYSCONF */
if (maxfd < 0) if (maxfd < OPEN_MAX)
maxfd = OPEN_MAX; maxfd = OPEN_MAX;
/* Make sure we did not get RLIM_INFINITY as the upper limit. */
if (maxfd > INT_MAX)
maxfd = INT_MAX;
for (fd = lowfd; fd < maxfd; fd++) for (fd = lowfd; fd < maxfd; fd++)
closefrom_close(fd); closefrom_close(fd);
} }
/* #if defined(HAVE_PSTAT_GETPROC)
* Close all file descriptors greater than or equal to lowfd. static int
* We try the fast way first, falling back on the slow method. closefrom_pstat(int lowfd)
*/
#if defined(HAVE_FCNTL_CLOSEM)
void
closefrom(int lowfd)
{ {
if (fcntl(lowfd, F_CLOSEM, 0) == -1) struct pst_status pst;
closefrom_fallback(lowfd);
}
#elif defined(HAVE_PSTAT_GETPROC)
void
closefrom(int lowfd)
{
struct pst_status pstat;
int fd; int fd;
if (pstat_getproc(&pstat, sizeof(pstat), 0, getpid()) != -1) { /*
for (fd = lowfd; fd <= pstat.pst_highestfd; fd++) * EOVERFLOW is not a fatal error for the fields we use.
* See the "EOVERFLOW Error" section of pstat_getvminfo(3).
*/
if (pstat_getproc(&pst, sizeof(pst), 0, getpid()) != -1 ||
errno == EOVERFLOW) {
for (fd = lowfd; fd <= pst.pst_highestfd; fd++)
(void)close(fd); (void)close(fd);
} else { return 0;
closefrom_fallback(lowfd);
} }
return -1;
} }
#elif defined(HAVE_DIRFD) #elif defined(HAVE_DIRFD)
static int static int
@@ -135,8 +139,8 @@ closefrom_procfs(int lowfd)
int ret = 0; int ret = 0;
int i; int i;
/* Use /proc/self/fd (or /dev/fd on FreeBSD) if it exists. */ /* Use /proc/self/fd (or /dev/fd on macOS) if it exists. */
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) # ifdef __APPLE__
path = "/dev/fd"; path = "/dev/fd";
# else # else
path = "/proc/self/fd"; path = "/proc/self/fd";
@@ -180,13 +184,36 @@ closefrom_procfs(int lowfd)
return ret; return ret;
} }
#endif
/*
* Close all file descriptors greater than or equal to lowfd.
* We try the fast way first, falling back on the slow method.
*/
void void
closefrom(int lowfd) closefrom(int lowfd)
{ {
if (closefrom_procfs(lowfd) == 0) if (lowfd < 0)
return; lowfd = 0;
/* Try the fast methods first, if possible. */
#if defined(HAVE_FCNTL_CLOSEM)
if (fcntl(lowfd, F_CLOSEM, 0) != -1)
return;
#endif /* HAVE_FCNTL_CLOSEM */
#if defined(__linux__) && defined(SYS_close_range)
if (sys_close_range(lowfd, UINT_MAX, 0) == 0)
return;
#endif
#if defined(HAVE_PSTAT_GETPROC)
if (closefrom_pstat(lowfd) != -1)
return;
#elif defined(HAVE_DIRFD)
if (closefrom_procfs(lowfd) != -1)
return;
#endif /* HAVE_DIRFD */
/* Do things the slow way. */
closefrom_fallback(lowfd); closefrom_fallback(lowfd);
} }
#endif /* HAVE_FCNTL_CLOSEM */

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: explicit_bzero.c,v 1.3 2014/06/21 02:34:26 matthew Exp $ */ /* $OpenBSD: explicit_bzero.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
/* /*
* Public domain. * Public domain.
* Written by Matthew Dempsky. * Written by Matthew Dempsky.
@@ -6,6 +6,9 @@
#include <string.h> #include <string.h>
__attribute__((__weak__)) void
__explicit_bzero_hook(void *, size_t);
__attribute__((__weak__)) void __attribute__((__weak__)) void
__explicit_bzero_hook(void *buf, size_t len) __explicit_bzero_hook(void *buf, size_t len)
{ {

View File

@@ -76,8 +76,8 @@ fgetln(FILE *stream, size_t *len)
} }
} }
libbsd_link_warning(fgetln, libbsd_link_warning(fgetln,
"This function cannot be safely ported, use getline(3) " "The fgetln() function cannot be safely ported, use getline(3) "
"instead, as it is supported by GNU and POSIX.1-2008.") "instead, as it is supported by GNU and POSIX.1-2008.");
#else #else
#error "Function fgetln() needs to be ported." #error "Function fgetln() needs to be ported."
#endif #endif

View File

@@ -88,5 +88,5 @@ fgetwln(FILE *stream, size_t *lenp)
return wused ? fb->wbuf : NULL; return wused ? fb->wbuf : NULL;
} }
libbsd_link_warning(fgetwln, libbsd_link_warning(fgetwln,
"This function cannot be safely ported, use fgetwc(3) " "The fgetwln() function cannot be safely ported, use fgetwc(3) "
"instead, as it is supported by C99 and POSIX.1-2001.") "instead, as it is supported by C99 and POSIX.1-2001.");

View File

@@ -26,6 +26,8 @@
#include <errno.h> #include <errno.h>
#include <stddef.h> #include <stddef.h>
int getentropy(void *buf, size_t len);
/* /*
* Derived from lib/libc/gen/arc4random.c from FreeBSD. * Derived from lib/libc/gen/arc4random.c from FreeBSD.
*/ */

View File

@@ -520,17 +520,17 @@ getentropy_fallback(void *buf, size_t len)
#ifdef HAVE_GETAUXVAL #ifdef HAVE_GETAUXVAL
#ifdef AT_RANDOM #ifdef AT_RANDOM
/* Not as random as you think but we take what we are given */ /* Not as random as you think but we take what we are given */
p = (char *) getauxval(AT_RANDOM); p = (char *) ((intptr_t) getauxval(AT_RANDOM));
if (p) if (p)
HR(p, 16); HR(p, 16);
#endif #endif
#ifdef AT_SYSINFO_EHDR #ifdef AT_SYSINFO_EHDR
p = (char *) getauxval(AT_SYSINFO_EHDR); p = (char *) ((intptr_t) getauxval(AT_SYSINFO_EHDR));
if (p) if (p)
HR(p, pgs); HR(p, pgs);
#endif #endif
#ifdef AT_BASE #ifdef AT_BASE
p = (char *) getauxval(AT_BASE); p = (char *) ((intptr_t) getauxval(AT_BASE));
if (p) if (p)
HD(p); HD(p);
#endif #endif

View File

@@ -8,4 +8,5 @@ Description: Utility functions from BSD systems (overlay)
Version: @VERSION@ Version: @VERSION@
URL: https://libbsd.freedesktop.org/ URL: https://libbsd.freedesktop.org/
Libs: -L${libdir} -lbsd Libs: -L${libdir} -lbsd
Libs.private: @LIBBSD_LIBS@ @MD5_LIBS@
Cflags: -isystem ${includedir}/bsd -DLIBBSD_OVERLAY Cflags: -isystem ${includedir}/bsd -DLIBBSD_OVERLAY

View File

@@ -8,4 +8,5 @@ Description: Utility functions from BSD systems
Version: @VERSION@ Version: @VERSION@
URL: https://libbsd.freedesktop.org/ URL: https://libbsd.freedesktop.org/
Libs: -L${libdir} -lbsd Libs: -L${libdir} -lbsd
Libs.private: @LIBBSD_LIBS@ @MD5_LIBS@
Cflags: -I${includedir} Cflags: -I${includedir}

View File

@@ -27,21 +27,44 @@
#ifndef LIBBSD_LOCAL_LINK_H #ifndef LIBBSD_LOCAL_LINK_H
#define LIBBSD_LOCAL_LINK_H #define LIBBSD_LOCAL_LINK_H
#include <sys/cdefs.h>
#define libbsd_link_warning(symbol, msg) \ #define libbsd_link_warning(symbol, msg) \
static const char libbsd_emit_link_warning_##symbol[] \ static const char libbsd_emit_link_warning_##symbol[] \
__attribute__((__used__,__section__(".gnu.warning." #symbol))) = msg; __attribute__((__used__,__section__(".gnu.warning." #symbol))) = msg
#ifdef __ELF__ #ifdef __ELF__
# if __has_attribute(symver)
/* The symver attribute is supported since gcc 10.x. */
#define libbsd_symver_default(alias, symbol, version) \
extern __typeof__(symbol) symbol \
__attribute__((__symver__(#alias "@@" #version)))
#define libbsd_symver_variant(alias, symbol, version) \
extern __typeof__(symbol) symbol \
__attribute__((__symver__(#alias "@" #version)))
#define libbsd_symver_weak(alias, symbol, version) \
extern __typeof__(symbol) symbol \
__attribute__((__symver__(#alias "@" #version), __weak__))
# else
#define libbsd_symver_default(alias, symbol, version) \ #define libbsd_symver_default(alias, symbol, version) \
__asm__(".symver " #symbol "," #alias "@@" #version) __asm__(".symver " #symbol "," #alias "@@" #version)
#define libbsd_symver_variant(alias, symbol, version) \ #define libbsd_symver_variant(alias, symbol, version) \
__asm__(".symver " #symbol "," #alias "@" #version) __asm__(".symver " #symbol "," #alias "@" #version)
#define libbsd_symver_weak(alias, symbol, version) \
libbsd_symver_variant(alias, symbol, version); \
extern __typeof__(symbol) alias \
__attribute__((__weak__))
# endif
#else #else
#define libbsd_symver_default(alias, symbol, version) \ #define libbsd_symver_default(alias, symbol, version) \
extern __typeof(symbol) alias __attribute__((__alias__(#symbol))) extern __typeof__(symbol) alias __attribute__((__alias__(#symbol)))
#define libbsd_symver_variant(alias, symbol, version) #define libbsd_symver_variant(alias, symbol, version)
#define libbsd_symver_weak(alias, symbol, version)
#endif #endif
#endif #endif

View File

@@ -27,65 +27,94 @@
#include <md5.h> #include <md5.h>
#include "local-link.h" #include "local-link.h"
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
void void
bsd_MD5Init(MD5_CTX *context) libbsd_MD5Init(MD5_CTX *context)
{ {
MD5Init(context); MD5Init(context);
} }
libbsd_symver_variant(MD5Init, bsd_MD5Init, LIBBSD_0.0); libbsd_link_warning(MD5Init,
"The MD5Init() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Init, libbsd_MD5Init, LIBBSD_0.0);
void void
bsd_MD5Update(MD5_CTX *context, const uint8_t *data, size_t len) libbsd_MD5Update(MD5_CTX *context, const uint8_t *data, size_t len)
{ {
MD5Update(context, data, len); MD5Update(context, data, len);
} }
libbsd_symver_variant(MD5Update, bsd_MD5Update, LIBBSD_0.0); libbsd_link_warning(MD5Update,
"The MD5Update() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Update, libbsd_MD5Update, LIBBSD_0.0);
void void
bsd_MD5Pad(MD5_CTX *context) libbsd_MD5Pad(MD5_CTX *context)
{ {
MD5Pad(context); MD5Pad(context);
} }
libbsd_symver_variant(MD5Pad, bsd_MD5Pad, LIBBSD_0.0); libbsd_link_warning(MD5Pad,
"The MD5Pad() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Pad, libbsd_MD5Pad, LIBBSD_0.0);
void void
bsd_MD5Final(uint8_t digest[MD5_DIGEST_LENGTH], MD5_CTX *context) libbsd_MD5Final(uint8_t digest[MD5_DIGEST_LENGTH], MD5_CTX *context)
{ {
MD5Final(digest, context); MD5Final(digest, context);
} }
libbsd_symver_variant(MD5Final, bsd_MD5Final, LIBBSD_0.0); libbsd_link_warning(MD5Final,
"The MD5Final() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Final, libbsd_MD5Final, LIBBSD_0.0);
void void
bsd_MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH]) libbsd_MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH])
{ {
MD5Transform(state, block); MD5Transform(state, block);
} }
libbsd_symver_variant(MD5Transform, bsd_MD5Transform, LIBBSD_0.0); libbsd_link_warning(MD5Transform,
"The MD5Transform() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Transform, libbsd_MD5Transform, LIBBSD_0.0);
char * char *
bsd_MD5End(MD5_CTX *context, char *buf) libbsd_MD5End(MD5_CTX *context, char *buf)
{ {
return MD5End(context, buf); return MD5End(context, buf);
} }
libbsd_symver_variant(MD5End, bsd_MD5End, LIBBSD_0.0); libbsd_link_warning(MD5End,
"The MD5End() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5End, libbsd_MD5End, LIBBSD_0.0);
char * char *
bsd_MD5File(const char *filename, char *buf) libbsd_MD5File(const char *filename, char *buf)
{ {
return MD5File(filename, buf); return MD5File(filename, buf);
} }
libbsd_symver_variant(MD5File, bsd_MD5File, LIBBSD_0.0); libbsd_link_warning(MD5File,
"The MD5File() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5File, libbsd_MD5File, LIBBSD_0.0);
char * char *
bsd_MD5FileChunk(const char *filename, char *buf, off_t offset, off_t length) libbsd_MD5FileChunk(const char *filename, char *buf, off_t offset, off_t length)
{ {
return MD5FileChunk(filename, buf, offset, length); return MD5FileChunk(filename, buf, offset, length);
} }
libbsd_symver_variant(MD5FileChunk, bsd_MD5FileChunk, LIBBSD_0.0); libbsd_link_warning(MD5FileChunk,
"The MD5FileChunk() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5FileChunk, libbsd_MD5FileChunk, LIBBSD_0.0);
char * char *
bsd_MD5Data(const uint8_t *data, size_t len, char *buf) libbsd_MD5Data(const uint8_t *data, size_t len, char *buf)
{ {
return MD5Data(data, len, buf); return MD5Data(data, len, buf);
} }
libbsd_symver_variant(MD5Data, bsd_MD5Data, LIBBSD_0.0); libbsd_link_warning(MD5Data,
"The MD5Data() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Data, libbsd_MD5Data, LIBBSD_0.0);

View File

@@ -43,10 +43,6 @@
#include "local-elf.h" #include "local-elf.h"
#ifndef SIZE_T_MAX
#define SIZE_T_MAX 0xffffffffU
#endif
/* Note: This function is used by libkvm0, so we need to export it. /* Note: This function is used by libkvm0, so we need to export it.
* It is not declared in the include files though. */ * It is not declared in the include files though. */
int __fdnlist(int, struct nlist *); int __fdnlist(int, struct nlist *);
@@ -153,7 +149,7 @@ __fdnlist(int fd, struct nlist *list)
shdr_size = ehdr.e_shentsize * ehdr.e_shnum; shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
/* Make sure it's not too big to mmap */ /* Make sure it's not too big to mmap */
if (shdr_size > SIZE_T_MAX || shdr_size > st.st_size) { if (shdr_size > st.st_size) {
errno = EFBIG; errno = EFBIG;
return (-1); return (-1);
} }
@@ -186,7 +182,7 @@ __fdnlist(int fd, struct nlist *list)
} }
/* Check for files too large to mmap. */ /* Check for files too large to mmap. */
if (symstrsize > SIZE_T_MAX || symstrsize > st.st_size) { if (symstrsize > st.st_size) {
errno = EFBIG; errno = EFBIG;
goto done; goto done;
} }
@@ -239,7 +235,6 @@ __fdnlist(int fd, struct nlist *list)
for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) { for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) {
char *name; char *name;
Elf_Word size; Elf_Word size;
struct nlist *p;
name = strtab + s->st_name; name = strtab + s->st_name;
if (name[0] == '\0') if (name[0] == '\0')

View File

@@ -222,6 +222,10 @@ setproctitle_init(int argc, char *argv[], char *envp[])
#define SPT_MAXTITLE 255 #define SPT_MAXTITLE 255
#endif #endif
__printflike(1, 2)
void
setproctitle_impl(const char *fmt, ...);
void void
setproctitle_impl(const char *fmt, ...) setproctitle_impl(const char *fmt, ...)
{ {

View File

@@ -49,4 +49,4 @@
* move them from .ctors to .init_array. * move them from .ctors to .init_array.
*/ */
void (*libbsd_init_func)(int argc, char *argv[], char *envp[]) void (*libbsd_init_func)(int argc, char *argv[], char *envp[])
__attribute__((__section__(".init_array"))) = setproctitle_init; __attribute__((__section__(".init_array"), __used__)) = setproctitle_init;

View File

@@ -564,12 +564,16 @@ strunvis(char *dst, const char *src)
* NetBSD: 2012, strnunvis(char *dst, size_t dlen, const char *src); * NetBSD: 2012, strnunvis(char *dst, size_t dlen, const char *src);
*/ */
ssize_t ssize_t
strnunvis_openbsd(char *, const char *, size_t);
ssize_t
strnunvis_openbsd(char *dst, const char *src, size_t dlen) strnunvis_openbsd(char *dst, const char *src, size_t dlen)
{ {
return strnunvisx(dst, dlen, src, 0); return strnunvisx(dst, dlen, src, 0);
} }
libbsd_symver_default(strnunvis, strnunvis_openbsd, LIBBSD_0.2); libbsd_symver_default(strnunvis, strnunvis_openbsd, LIBBSD_0.2);
int
strnunvis_netbsd(char *, size_t, const char *);
int int
strnunvis_netbsd(char *dst, size_t dlen, const char *src) strnunvis_netbsd(char *dst, size_t dlen, const char *src)
{ {

View File

@@ -733,12 +733,16 @@ strvis(char *mbdst, const char *mbsrc, int flags)
* NetBSD: 2012, strnvis(char *dst, size_t dlen, const char *src, int flag); * NetBSD: 2012, strnvis(char *dst, size_t dlen, const char *src, int flag);
*/ */
int int
strnvis_openbsd(char *, const char *, size_t, int);
int
strnvis_openbsd(char *mbdst, const char *mbsrc, size_t dlen, int flags) strnvis_openbsd(char *mbdst, const char *mbsrc, size_t dlen, int flags)
{ {
return istrsenvisxl(mbdst, &dlen, mbsrc, flags, "", NULL); return istrsenvisxl(mbdst, &dlen, mbsrc, flags, "", NULL);
} }
libbsd_symver_default(strnvis, strnvis_openbsd, LIBBSD_0.2); libbsd_symver_default(strnvis, strnvis_openbsd, LIBBSD_0.2);
int
strnvis_netbsd(char *, size_t, const char *, int);
int int
strnvis_netbsd(char *mbdst, size_t dlen, const char *mbsrc, int flags) strnvis_netbsd(char *mbdst, size_t dlen, const char *mbsrc, int flags)
{ {

View File

@@ -41,6 +41,7 @@ check_PROGRAMS = \
fpurge \ fpurge \
md5 \ md5 \
nlist \ nlist \
proctitle \
proctitle-init \ proctitle-init \
progname \ progname \
pwcache \ pwcache \
@@ -52,8 +53,6 @@ check_PROGRAMS = \
vis-openbsd \ vis-openbsd \
$(nil) $(nil)
md5_LDADD = $(LDADD) $(MD_LIBS)
if HAVE_LIBTESTU01 if HAVE_LIBTESTU01
arc4random_LDADD = $(LDADD) $(TESTU01_LIBS) arc4random_LDADD = $(LDADD) $(TESTU01_LIBS)
@@ -70,6 +69,11 @@ proctitle_LDFLAGS = \
check_PROGRAMS += proctitle check_PROGRAMS += proctitle
endif endif
if NEED_TRANSPARENT_LIBMD
# On the installed system this is handled via the ld script.
md5_LDADD = $(LDADD) $(MD5_LIBS)
endif
fgetln_SOURCES = test-stream.c test-stream.h fgetln.c fgetln_SOURCES = test-stream.c test-stream.h fgetln.c
fgetln_CFLAGS = -Wno-deprecated-declarations fgetln_CFLAGS = -Wno-deprecated-declarations
fparseln_SOURCES = test-stream.c test-stream.h fparseln.c fparseln_SOURCES = test-stream.c test-stream.h fparseln.c

View File

@@ -28,7 +28,7 @@
#include <string.h> #include <string.h>
int int
main() main(int argc, char *argv[])
{ {
unsigned char array[40]; unsigned char array[40];
size_t i; size_t i;

View File

@@ -31,7 +31,7 @@
#include <stdio.h> #include <stdio.h>
int int
main() main(int argc, char *argv[])
{ {
int i; int i;
int fd; int fd;

View File

@@ -30,7 +30,7 @@
#include <string.h> #include <string.h>
int int
main() main(int argc, char *argv[])
{ {
unsigned char decstream[] = { unsigned char decstream[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,

View File

@@ -75,7 +75,7 @@ test_fgetln_single(void)
size_t len; size_t len;
int i; int i;
fp = pipe_feed("%s", (const void **)data_ascii, DATA_LINES); fp = pipe_feed(PIPE_DATA_ASCII, (const void **)data_ascii, DATA_LINES);
for (i = 0; i < DATA_LINES; i++) { for (i = 0; i < DATA_LINES; i++) {
char *str = fgetln(fp, &len); char *str = fgetln(fp, &len);
@@ -96,13 +96,14 @@ test_fgetln_multi(void)
char *str; char *str;
str = strdup("A\n"); str = strdup("A\n");
assert(str);
str[0] += i; str[0] += i;
files[i].line_alloc = str; files[i].line_alloc = str;
files[i].lines = reallocarray(NULL, LINE_COUNT, sizeof(char *)); files[i].lines = reallocarray(NULL, LINE_COUNT, sizeof(char *));
files[i].lines[0] = str; files[i].lines[0] = str;
files[i].lines[1] = str; files[i].lines[1] = str;
files[i].fp = pipe_feed("%s", files[i].lines, LINE_COUNT); files[i].fp = pipe_feed(PIPE_DATA_ASCII, files[i].lines, LINE_COUNT);
} }
for (l = 0; l < LINE_COUNT; l++) { for (l = 0; l < LINE_COUNT; l++) {
@@ -139,7 +140,7 @@ test_fgetwln_single(void)
size_t len; size_t len;
int i; int i;
fp = pipe_feed("%ls", (const void **)data_wide, DATA_LINES); fp = pipe_feed(PIPE_DATA_WIDE, (const void **)data_wide, DATA_LINES);
for (i = 0; i < DATA_LINES; i++) { for (i = 0; i < DATA_LINES; i++) {
wchar_t *wstr; wchar_t *wstr;
@@ -168,7 +169,7 @@ test_fgetwln_multi(void)
files[i].lines = reallocarray(NULL, LINE_COUNT, sizeof(char *)); files[i].lines = reallocarray(NULL, LINE_COUNT, sizeof(char *));
files[i].lines[0] = wstr; files[i].lines[0] = wstr;
files[i].lines[1] = wstr; files[i].lines[1] = wstr;
files[i].fp = pipe_feed("%ls", files[i].lines, LINE_COUNT); files[i].fp = pipe_feed(PIPE_DATA_WIDE, files[i].lines, LINE_COUNT);
} }
for (l = 0; l < LINE_COUNT; l++) { for (l = 0; l < LINE_COUNT; l++) {

View File

@@ -68,7 +68,7 @@ test_fparseln(const char **data_expect, int flags)
FILE *fp; FILE *fp;
size_t i, len, lineno = 0; size_t i, len, lineno = 0;
fp = pipe_feed("%s", (const void **)data_test, TEST_LINES); fp = pipe_feed(PIPE_DATA_ASCII, (const void **)data_test, TEST_LINES);
for (i = 0; i < EXPECT_LINES; i++) { for (i = 0; i < EXPECT_LINES; i++) {
char *str = fparseln(fp, &len, &lineno, NULL, flags); char *str = fparseln(fp, &len, &lineno, NULL, flags);

View File

@@ -27,7 +27,7 @@
#include <stdio.h> #include <stdio.h>
int int
main() main(int argc, char *argv[])
{ {
static FILE fp_bad; static FILE fp_bad;
FILE *fp; FILE *fp;

View File

@@ -37,7 +37,7 @@ struct test_cookie {
int index; int index;
}; };
int static int
test_readfn(void *cookie, char *buf, int size) test_readfn(void *cookie, char *buf, int size)
{ {
struct test_cookie *tc = cookie; struct test_cookie *tc = cookie;
@@ -56,7 +56,7 @@ test_readfn(void *cookie, char *buf, int size)
return size; return size;
} }
int static int
test_writefn(void *cookie, const char *buf, int size) test_writefn(void *cookie, const char *buf, int size)
{ {
struct test_cookie *tc = cookie; struct test_cookie *tc = cookie;
@@ -75,7 +75,7 @@ test_writefn(void *cookie, const char *buf, int size)
return size; return size;
} }
off_t static off_t
test_seekfn(void *cookie, off_t offset, int whence) test_seekfn(void *cookie, off_t offset, int whence)
{ {
struct test_cookie *tc = cookie; struct test_cookie *tc = cookie;
@@ -95,7 +95,7 @@ test_seekfn(void *cookie, off_t offset, int whence)
return tc->index; return tc->index;
} }
int static int
test_closefn(void *cookie) test_closefn(void *cookie)
{ {
struct test_cookie *tc = cookie; struct test_cookie *tc = cookie;
@@ -114,7 +114,7 @@ main(int argc, char **argv)
size_t i; size_t i;
/* Test invalid hooks. */ /* Test invalid hooks. */
fp = funopen(&tc, NULL, NULL, NULL, NULL); fp = funopen(NULL, NULL, NULL, NULL, NULL);
assert(fp == NULL); assert(fp == NULL);
assert(errno == EINVAL); assert(errno == EINVAL);

View File

@@ -28,7 +28,7 @@
#include <md5.h> #include <md5.h>
#include <string.h> #include <string.h>
void static void
test_md5(const char *digest, const char *string) test_md5(const char *digest, const char *string)
{ {
char result[MD5_DIGEST_STRING_LENGTH]; char result[MD5_DIGEST_STRING_LENGTH];
@@ -37,7 +37,7 @@ test_md5(const char *digest, const char *string)
} }
int int
main() main(int argc, char *argv[])
{ {
test_md5("d41d8cd98f00b204e9800998ecf8427e", ""); test_md5("d41d8cd98f00b204e9800998ecf8427e", "");
test_md5("900150983cd24fb0d6963f7d28e17f72", "abc"); test_md5("900150983cd24fb0d6963f7d28e17f72", "abc");

View File

@@ -39,11 +39,11 @@ extern int data_pub_uninit[2048];
extern int *data_pub_ptr; extern int *data_pub_ptr;
int *data_pub_ptr = &data_prv_init; int *data_pub_ptr = &data_prv_init;
int data_pub_init = 10; int data_pub_init __attribute__((__used__)) = 10;
int data_pub_uninit[2048]; int data_pub_uninit[2048] __attribute__((__used__));
extern int extern int
func_pub(void); func_pub(void) __attribute__((__used__)) ;
int int
func_pub(void) func_pub(void)
@@ -55,11 +55,11 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
struct nlist nl[] = { struct nlist nl[] = {
{ .n_un.n_name = "main" }, { .n_un.n_name = (char *)"main" },
{ .n_un.n_name = "func_pub" }, { .n_un.n_name = (char *)"func_pub" },
{ .n_un.n_name = "data_pub_uninit" }, { .n_un.n_name = (char *)"data_pub_uninit" },
{ .n_un.n_name = "data_pub_init" }, { .n_un.n_name = (char *)"data_pub_init" },
{ .n_un.n_name = "data_prv_init" }, { .n_un.n_name = (char *)"data_prv_init" },
{ .n_un.n_name = NULL }, { .n_un.n_name = NULL },
}; };
int rc; int rc;

View File

@@ -45,7 +45,7 @@
#include <unistd.h> #include <unistd.h>
int int
main() main(int argc, char *argv[])
{ {
/* Test that we do not get partial definitions. */ /* Test that we do not get partial definitions. */
fflush(stdout); fflush(stdout);

View File

@@ -35,11 +35,15 @@ main(int argc, char **argv)
assert(strnstr(large, "", strlen(large)) == large); assert(strnstr(large, "", strlen(large)) == large);
assert(strnstr(large, "far", strlen(large)) == NULL);
assert(strnstr(large, "quux", strlen(large)) == NULL); assert(strnstr(large, "quux", strlen(large)) == NULL);
assert(strnstr(large, small, 4) == NULL); assert(strnstr(large, small, 4) == NULL);
assert(strnstr(large, small, strlen(large)) == (large + 4)); assert(strnstr(large, small, strlen(large)) == (large + 4));
assert(strnstr("quux", large, strlen("quux")) == NULL);
assert(strnstr("foo", large, strlen("foo")) == NULL);
return 0; return 0;
} }

View File

@@ -27,12 +27,13 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <wchar.h>
#include <stdio.h> #include <stdio.h>
#include "test-stream.h" #include "test-stream.h"
FILE * FILE *
pipe_feed(const char *fmt, const void **buf, int buf_nmemb) pipe_feed(enum pipe_data_mode mode, const void **buf, int buf_nmemb)
{ {
FILE *fp; FILE *fp;
int rc; int rc;
@@ -56,7 +57,10 @@ pipe_feed(const char *fmt, const void **buf, int buf_nmemb)
assert(fp); assert(fp);
for (line = 0; line < buf_nmemb; line++) { for (line = 0; line < buf_nmemb; line++) {
rc = fprintf(fp, fmt, buf[line]); if (mode == PIPE_DATA_ASCII)
rc = fprintf(fp, "%s", (const char *)buf[line]);
else
rc = fprintf(fp, "%ls", (const wchar_t *)buf[line]);
assert(rc >= 0); assert(rc >= 0);
} }

View File

@@ -29,8 +29,13 @@
#include <stdio.h> #include <stdio.h>
enum pipe_data_mode {
PIPE_DATA_ASCII,
PIPE_DATA_WIDE,
};
FILE * FILE *
pipe_feed(const char *fmt, const void **buf, int buf_nmemb); pipe_feed(enum pipe_data_mode mode, const void **buf, int buf_nmemb);
void void
pipe_close(FILE *fp); pipe_close(FILE *fp);

View File

@@ -24,12 +24,11 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#define LIBBSD_OPENBSD_VIS 1
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcpp"
#include <vis.h> #include <vis.h>
#pragma GCC diagnostic pop
int int
main(int argc, char **argv) main(int argc, char **argv)