| .\" 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 2021-03-22 "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) |