mirror of https://github.com/mkerrisk/man-pages
417 lines
12 KiB
Groff
417 lines
12 KiB
Groff
.\" Copyright (c) 1993
|
|
.\" The Regents of the University of California. All rights reserved.
|
|
.\" and Copyright (c) 2020 by Alejandro Colomar <colomar.6.4.3@gmail.com>
|
|
.\"
|
|
.\" %%%LICENSE_START(BSD_3_CLAUSE_UCB)
|
|
.\" Redistribution and use in source and binary forms, with or without
|
|
.\" modification, are permitted provided that the following conditions
|
|
.\" are met:
|
|
.\" 1. Redistributions of source code must retain the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer.
|
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer in the
|
|
.\" documentation and/or other materials provided with the distribution.
|
|
.\" 3. Neither the name of the University nor the names of its contributors
|
|
.\" may be used to endorse or promote products derived from this software
|
|
.\" without specific prior written permission.
|
|
.\"
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
.\" SUCH DAMAGE.
|
|
.\" %%%LICENSE_END
|
|
.\"
|
|
.\"
|
|
.TH TAILQ 3 2020-12-21 "GNU" "Linux Programmer's Manual"
|
|
.SH NAME
|
|
TAILQ_CONCAT,
|
|
TAILQ_EMPTY,
|
|
TAILQ_ENTRY,
|
|
TAILQ_FIRST,
|
|
TAILQ_FOREACH,
|
|
.\"TAILQ_FOREACH_FROM,
|
|
.\"TAILQ_FOREACH_FROM_SAFE,
|
|
TAILQ_FOREACH_REVERSE,
|
|
.\"TAILQ_FOREACH_REVERSE_FROM,
|
|
.\"TAILQ_FOREACH_REVERSE_FROM_SAFE,
|
|
.\"TAILQ_FOREACH_REVERSE_SAFE,
|
|
.\"TAILQ_FOREACH_SAFE,
|
|
TAILQ_HEAD,
|
|
TAILQ_HEAD_INITIALIZER,
|
|
TAILQ_INIT,
|
|
TAILQ_INSERT_AFTER,
|
|
TAILQ_INSERT_BEFORE,
|
|
TAILQ_INSERT_HEAD,
|
|
TAILQ_INSERT_TAIL,
|
|
TAILQ_LAST,
|
|
TAILQ_NEXT,
|
|
TAILQ_PREV,
|
|
TAILQ_REMOVE
|
|
.\"TAILQ_SWAP
|
|
\- implementation of a doubly linked tail queue
|
|
.SH SYNOPSIS
|
|
.nf
|
|
.B #include <sys/queue.h>
|
|
.PP
|
|
.B TAILQ_ENTRY(TYPE);
|
|
.PP
|
|
.B TAILQ_HEAD(HEADNAME, TYPE);
|
|
.BI "TAILQ_HEAD TAILQ_HEAD_INITIALIZER(TAILQ_HEAD " head );
|
|
.BI "void TAILQ_INIT(TAILQ_HEAD *" head );
|
|
.PP
|
|
.BI "int TAILQ_EMPTY(TAILQ_HEAD *" head );
|
|
.PP
|
|
.BI "void TAILQ_INSERT_HEAD(TAILQ_HEAD *" head ,
|
|
.BI " struct TYPE *" elm ", TAILQ_ENTRY " NAME );
|
|
.BI "void TAILQ_INSERT_TAIL(TAILQ_HEAD *" head ,
|
|
.BI " struct TYPE *" elm ", TAILQ_ENTRY " NAME );
|
|
.BI "void TAILQ_INSERT_BEFORE(struct TYPE *" listelm ,
|
|
.BI " struct TYPE *" elm ", TAILQ_ENTRY " NAME );
|
|
.BI "void TAILQ_INSERT_AFTER(TAILQ_HEAD *" head ", struct TYPE *" listelm ,
|
|
.BI " struct TYPE *" elm ", TAILQ_ENTRY " NAME );
|
|
.PP
|
|
.BI "struct TYPE *TAILQ_FIRST(TAILQ_HEAD *" head );
|
|
.BI "struct TYPE *TAILQ_LAST(TAILQ_HEAD *" head ", HEADNAME);"
|
|
.BI "struct TYPE *TAILQ_PREV(struct TYPE *" elm ", HEADNAME, TAILQ_ENTRY " NAME );
|
|
.BI "struct TYPE *TAILQ_NEXT(struct TYPE *" elm ", TAILQ_ENTRY " NAME );
|
|
.PP
|
|
.BI "TAILQ_FOREACH(struct TYPE *" var ", TAILQ_HEAD *" head ,
|
|
.BI " TAILQ_ENTRY " NAME );
|
|
.\" .BI "TAILQ_FOREACH_FROM(struct TYPE *" var ", TAILQ_HEAD *" head ,
|
|
.\" .BI " TAILQ_ENTRY " NAME );
|
|
.BI "TAILQ_FOREACH_REVERSE(struct TYPE *" var ", TAILQ_HEAD *" head ", HEADNAME,"
|
|
.BI " TAILQ_ENTRY " NAME );
|
|
.\" .BI "TAILQ_FOREACH_REVERSE_FROM(struct TYPE *" var ", TAILQ_HEAD *" head ", HEADNAME,"
|
|
.\" .BI " TAILQ_ENTRY " NAME );
|
|
.\" .PP
|
|
.\" .BI "TAILQ_FOREACH_SAFE(struct TYPE *" var ", TAILQ_HEAD *" head ,
|
|
.\" .BI " TAILQ_ENTRY " NAME ,
|
|
.\" .BI " struct TYPE *" temp_var );
|
|
.\" .BI "TAILQ_FOREACH_FROM_SAFE(struct TYPE *" var ", TAILQ_HEAD *" head ,
|
|
.\" .BI " TAILQ_ENTRY " NAME ,
|
|
.\" .BI " struct TYPE *" temp_var );
|
|
.\" .BI "TAILQ_FOREACH_REVERSE_SAFE(struct TYPE *" var ", TAILQ_HEAD *" head ,
|
|
.\" .BI " HEADNAME, TAILQ_ENTRY " NAME ,
|
|
.\" .BI " struct TYPE *" temp_var );
|
|
.\" .BI "TAILQ_FOREACH_REVERSE_FROM_SAFE(struct TYPE *" var ", TAILQ_HEAD *" head ,
|
|
.\" .BI " HEADNAME, TAILQ_ENTRY " NAME ,
|
|
.\" .BI " struct TYPE *" temp_var );
|
|
.PP
|
|
.BI "void TAILQ_REMOVE(TAILQ_HEAD *" head ", struct TYPE *" elm ,
|
|
.BI " TAILQ_ENTRY " NAME );
|
|
.PP
|
|
.BI "void TAILQ_CONCAT(TAILQ_HEAD *" head1 ", TAILQ_HEAD *" head2 ,
|
|
.BI " TAILQ_ENTRY " NAME );
|
|
.\" .BI "void TAILQ_SWAP(TAILQ_HEAD *" head1 ", TAILQ_HEAD *" head2 ", TYPE,"
|
|
.\" .BI " TAILQ_ENTRY " NAME );
|
|
.fi
|
|
.SH DESCRIPTION
|
|
These macros define and operate on doubly linked tail queues.
|
|
.PP
|
|
In the macro definitions,
|
|
.I TYPE
|
|
is the name of a user defined structure,
|
|
that must contain a field of type
|
|
.IR TAILQ_ENTRY ,
|
|
named
|
|
.IR NAME .
|
|
The argument
|
|
.I HEADNAME
|
|
is the name of a user defined structure that must be declared
|
|
using the macro
|
|
.BR TAILQ_HEAD ().
|
|
.SS Creation
|
|
A tail queue is headed by a structure defined by the
|
|
.BR TAILQ_HEAD ()
|
|
macro.
|
|
This structure contains a pair of pointers,
|
|
one to the first element in the queue
|
|
and the other to the last element in the queue.
|
|
The elements are doubly linked
|
|
so that an arbitrary element can be removed without traversing the queue.
|
|
New elements can be added to the queue
|
|
after an existing element,
|
|
before an existing element,
|
|
at the head of the queue,
|
|
or at the end of the queue.
|
|
A
|
|
.I TAILQ_HEAD
|
|
structure is declared as follows:
|
|
.PP
|
|
.in +4
|
|
.EX
|
|
TAILQ_HEAD(HEADNAME, TYPE) head;
|
|
.EE
|
|
.in
|
|
.PP
|
|
where
|
|
.I struct HEADNAME
|
|
is the structure to be defined, and
|
|
.I struct TYPE
|
|
is the type of the elements to be linked into the queue.
|
|
A pointer to the head of the queue can later be declared as:
|
|
.PP
|
|
.in +4
|
|
.EX
|
|
struct HEADNAME *headp;
|
|
.EE
|
|
.in
|
|
.PP
|
|
(The names
|
|
.I head
|
|
and
|
|
.I headp
|
|
are user selectable.)
|
|
.PP
|
|
.BR TAILQ_ENTRY ()
|
|
declares a structure that connects the elements in the queue.
|
|
.PP
|
|
.BR TAILQ_HEAD_INITIALIZER ()
|
|
evaluates to an initializer for the queue
|
|
.IR head .
|
|
.PP
|
|
.BR TAILQ_INIT ()
|
|
initializes the queue referenced by
|
|
.PP
|
|
.BR TAILQ_EMPTY ()
|
|
evaluates to true if there are no items on the queue.
|
|
.IR head .
|
|
.SS Insertion
|
|
.BR TAILQ_INSERT_HEAD ()
|
|
inserts the new element
|
|
.I elm
|
|
at the head of the queue.
|
|
.PP
|
|
.BR TAILQ_INSERT_TAIL ()
|
|
inserts the new element
|
|
.I elm
|
|
at the end of the queue.
|
|
.PP
|
|
.BR TAILQ_INSERT_BEFORE ()
|
|
inserts the new element
|
|
.I elm
|
|
before the element
|
|
.IR listelm .
|
|
.PP
|
|
.BR TAILQ_INSERT_AFTER ()
|
|
inserts the new element
|
|
.I elm
|
|
after the element
|
|
.IR listelm .
|
|
.SS Traversal
|
|
.BR TAILQ_FIRST ()
|
|
returns the first item on the queue, or NULL if the queue is empty.
|
|
.PP
|
|
.BR TAILQ_LAST ()
|
|
returns the last item on the queue.
|
|
If the queue is empty the return value is NULL.
|
|
.PP
|
|
.BR TAILQ_PREV ()
|
|
returns the previous item on the queue, or NULL if this item is the first.
|
|
.PP
|
|
.BR TAILQ_NEXT ()
|
|
returns the next item on the queue, or NULL if this item is the last.
|
|
.PP
|
|
.BR TAILQ_FOREACH ()
|
|
traverses the queue referenced by
|
|
.I head
|
|
in the forward direction,
|
|
assigning each element in turn to
|
|
.IR var .
|
|
.I var
|
|
is set to NULL if the loop completes normally,
|
|
or if there were no elements.
|
|
.\" .PP
|
|
.\" .BR TAILQ_FOREACH_FROM ()
|
|
.\" behaves identically to
|
|
.\" .BR TAILQ_FOREACH ()
|
|
.\" when
|
|
.\" .I var
|
|
.\" is NULL, else it treats
|
|
.\" .I var
|
|
.\" as a previously found TAILQ element and begins the loop at
|
|
.\" .I var
|
|
.\" instead of the first element in the TAILQ referenced by
|
|
.\" .IR head .
|
|
.PP
|
|
.BR TAILQ_FOREACH_REVERSE ()
|
|
traverses the queue referenced by
|
|
.I head
|
|
in the reverse direction,
|
|
assigning each element in turn to
|
|
.IR var .
|
|
.\" .PP
|
|
.\" .BR TAILQ_FOREACH_REVERSE_FROM ()
|
|
.\" behaves identically to
|
|
.\" .BR TAILQ_FOREACH_REVERSE ()
|
|
.\" when
|
|
.\" .I var
|
|
.\" is NULL, else it treats
|
|
.\" .I var
|
|
.\" as a previously found TAILQ element and begins the reverse loop at
|
|
.\" .I var
|
|
.\" instead of the last element in the TAILQ referenced by
|
|
.\" .IR head .
|
|
.\" .PP
|
|
.\" .BR TAILQ_FOREACH_SAFE ()
|
|
.\" and
|
|
.\" .BR TAILQ_FOREACH_REVERSE_SAFE ()
|
|
.\" traverse the list referenced by
|
|
.\" .I head
|
|
.\" in the forward or reverse direction respectively,
|
|
.\" assigning each element in turn to
|
|
.\" .IR var .
|
|
.\" However, unlike their unsafe counterparts,
|
|
.\" .BR TAILQ_FOREACH ()
|
|
.\" and
|
|
.\" .BR TAILQ_FOREACH_REVERSE ()
|
|
.\" permit to both remove
|
|
.\" .I var
|
|
.\" as well as free it from within the loop safely without interfering with the
|
|
.\" traversal.
|
|
.\" .PP
|
|
.\" .BR TAILQ_FOREACH_FROM_SAFE ()
|
|
.\" behaves identically to
|
|
.\" .BR TAILQ_FOREACH_SAFE ()
|
|
.\" when
|
|
.\" .I var
|
|
.\" is NULL, else it treats
|
|
.\" .I var
|
|
.\" as a previously found TAILQ element and begins the loop at
|
|
.\" .I var
|
|
.\" instead of the first element in the TAILQ referenced by
|
|
.\" .IR head .
|
|
.\" .PP
|
|
.\" .BR TAILQ_FOREACH_REVERSE_FROM_SAFE ()
|
|
.\" behaves identically to
|
|
.\" .BR TAILQ_FOREACH_REVERSE_SAFE ()
|
|
.\" when
|
|
.\" .I var
|
|
.\" is NULL, else it treats
|
|
.\" .I var
|
|
.\" as a previously found TAILQ element and begins the reverse loop at
|
|
.\" .I var
|
|
.\" instead of the last element in the TAILQ referenced by
|
|
.\" .IR head .
|
|
.SS Removal
|
|
.BR TAILQ_REMOVE ()
|
|
removes the element
|
|
.I elm
|
|
from the queue.
|
|
.SS Other features
|
|
.\" .BR TAILQ_SWAP ()
|
|
.\" swaps the contents of
|
|
.\" .I head1
|
|
.\" and
|
|
.\" .IR head2 .
|
|
.\" .PP
|
|
.BR TAILQ_CONCAT ()
|
|
concatenates the queue headed by
|
|
.I head2
|
|
onto the end of the one headed by
|
|
.I head1
|
|
removing all entries from the former.
|
|
.SH RETURN VALUE
|
|
.BR TAILQ_EMPTY ()
|
|
returns nonzero if the queue is empty,
|
|
and zero if the queue contains at least one entry.
|
|
.PP
|
|
.BR TAILQ_FIRST (),
|
|
.BR TAILQ_LAST (),
|
|
.BR TAILQ_PREV (),
|
|
and
|
|
.BR TAILQ_NEXT ()
|
|
return a pointer to the first, last, previous, or next
|
|
.I TYPE
|
|
structure, respectively.
|
|
.PP
|
|
.BR TAILQ_HEAD_INITIALIZER ()
|
|
returns an initializer that can be assigned to the queue
|
|
.IR head .
|
|
.SH CONFORMING TO
|
|
Not in POSIX.1, POSIX.1-2001, or POSIX.1-2008.
|
|
Present on the BSDs.
|
|
(TAILQ functions first appeared in 4.4BSD).
|
|
.SH BUGS
|
|
.BR TAILQ_FOREACH ()
|
|
and
|
|
.BR TAILQ_FOREACH_REVERSE ()
|
|
don't allow
|
|
.I var
|
|
to be removed or freed within the loop,
|
|
as it would interfere with the traversal.
|
|
.BR TAILQ_FOREACH_SAFE ()
|
|
and
|
|
.BR TAILQ_FOREACH_REVERSE_SAFE (),
|
|
which are present on the BSDs but are not present in glibc,
|
|
fix this limitation by allowing
|
|
.I var
|
|
to safely be removed from the list and freed from within the loop
|
|
without interfering with the traversal.
|
|
.SH EXAMPLES
|
|
.EX
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/queue.h>
|
|
|
|
struct entry {
|
|
int data;
|
|
TAILQ_ENTRY(entry) entries; /* Tail queue */
|
|
};
|
|
|
|
TAILQ_HEAD(tailhead, entry);
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
struct entry *n1, *n2, *n3, *np;
|
|
struct tailhead head; /* Tail queue head */
|
|
int i;
|
|
|
|
TAILQ_INIT(&head); /* Initialize the queue */
|
|
|
|
n1 = malloc(sizeof(struct entry)); /* Insert at the head */
|
|
TAILQ_INSERT_HEAD(&head, n1, entries);
|
|
|
|
n1 = malloc(sizeof(struct entry)); /* Insert at the tail */
|
|
TAILQ_INSERT_TAIL(&head, n1, entries);
|
|
|
|
n2 = malloc(sizeof(struct entry)); /* Insert after */
|
|
TAILQ_INSERT_AFTER(&head, n1, n2, entries);
|
|
|
|
n3 = malloc(sizeof(struct entry)); /* Insert before */
|
|
TAILQ_INSERT_BEFORE(n2, n3, entries);
|
|
|
|
TAILQ_REMOVE(&head, n2, entries); /* Deletion */
|
|
free(n2);
|
|
/* Forward traversal */
|
|
i = 0;
|
|
TAILQ_FOREACH(np, &head, entries)
|
|
np\->data = i++;
|
|
/* Reverse traversal */
|
|
TAILQ_FOREACH_REVERSE(np, &head, tailhead, entries)
|
|
printf("%i\en", np\->data);
|
|
/* TailQ deletion */
|
|
n1 = TAILQ_FIRST(&head);
|
|
while (n1 != NULL) {
|
|
n2 = TAILQ_NEXT(n1, entries);
|
|
free(n1);
|
|
n1 = n2;
|
|
}
|
|
TAILQ_INIT(&head);
|
|
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
.EE
|
|
.SH SEE ALSO
|
|
.BR insque (3),
|
|
.BR queue (7)
|