mirror of
https://github.com/rkd77/elinks.git
synced 2024-11-04 08:17:17 -05:00
233 lines
5.8 KiB
C
233 lines
5.8 KiB
C
|
#ifndef EL__UTIL_LISTS_H
|
||
|
#define EL__UTIL_LISTS_H
|
||
|
|
||
|
#include "util/error.h" /* do_not_optimize_here() */
|
||
|
|
||
|
/* BEWARE! You MAY NOT use ternary operator as parameter to there functions,
|
||
|
* because they are likely to take & of the parameter. Worst of all, it will
|
||
|
* work with gcc. But nowhere else (at least not w/ tcc). */
|
||
|
|
||
|
/* Note that this whole lists implementation code is severely broken. All of
|
||
|
* it is a single huge violation of C aliasing rules, just accessing things
|
||
|
* like we do here is totally prohibited and bound to generate segfaults in
|
||
|
* proportion with rising optimization level and gcc version.
|
||
|
*
|
||
|
* Fixing this would be a nice and needed janitorial project. */
|
||
|
|
||
|
/* Lists debugging
|
||
|
* Two unsigned int magic number will be put before and after the next and
|
||
|
* prev pointers, these will be check on list operations.
|
||
|
* Some pointers are set to specific values after action. */
|
||
|
#ifdef CONFIG_DEBUG
|
||
|
#define LISTDEBUG
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* Fix namespace clash with system headers (like FreeBSD's, all hail BSD!). */
|
||
|
#undef LIST_HEAD
|
||
|
#undef list_head
|
||
|
#define list_head list_head_elinks
|
||
|
|
||
|
|
||
|
#ifndef LISTDEBUG
|
||
|
|
||
|
#define list_del_enforce(x) /* better don't */
|
||
|
|
||
|
#define list_magic_error(where, what) /* no magic */
|
||
|
|
||
|
#define list_magic_set(x) /* no magic */
|
||
|
|
||
|
#define list_magic_correct(x) (1)
|
||
|
#define list_magic_check(x, where) /* no magic */
|
||
|
#define list_magic_chkbool(x, where) (1)
|
||
|
|
||
|
struct list_head {
|
||
|
void *next;
|
||
|
void *prev;
|
||
|
};
|
||
|
|
||
|
struct xlist_head {
|
||
|
struct xlist_head *next;
|
||
|
struct xlist_head *prev;
|
||
|
};
|
||
|
|
||
|
#define NULL_LIST_HEAD NULL, NULL
|
||
|
#define D_LIST_HEAD(x) &x, &x
|
||
|
#define LIST_HEAD(x) x *next; x *prev
|
||
|
#define LIST_SET_MAGIC(x) list_magic_set(*(x))
|
||
|
|
||
|
|
||
|
#else /* LISTDEBUG */
|
||
|
|
||
|
#define LISTMAGIC1 ((void *) 0xdadababa)
|
||
|
#define LISTMAGIC2 ((void *) 0xd0d0b0b0)
|
||
|
#define LISTMAGIC3 ((void *) 0x25254545)
|
||
|
|
||
|
#define list_del_enforce(x) \
|
||
|
do { \
|
||
|
/* Little hack: we put LISTMAGIC3 in prev */ \
|
||
|
/* and the line number in next. Debugging purpose. */ \
|
||
|
(x)->prev = LISTMAGIC3; \
|
||
|
(x)->next = (void *) ((unsigned int) __LINE__); \
|
||
|
} while (0)
|
||
|
|
||
|
|
||
|
#define list_magic_error(where,what) INTERNAL("[%s] %s - bad list magic", where, #what)
|
||
|
|
||
|
|
||
|
#define list_magic_set(x) \
|
||
|
do { \
|
||
|
(x).magic1 = LISTMAGIC1; \
|
||
|
(x).magic2 = LISTMAGIC2; \
|
||
|
} while (0)
|
||
|
|
||
|
|
||
|
/* Backend for list_magic_check() and list_magic_chkbool(). */
|
||
|
#define list_magic_correct(x) ((x).magic1 == LISTMAGIC1 && (x).magic2 == LISTMAGIC2)
|
||
|
|
||
|
#define list_magic_check(x, where) \
|
||
|
do { \
|
||
|
if (!list_magic_correct(*(x))) \
|
||
|
list_magic_error(where, x); \
|
||
|
} while (0)
|
||
|
|
||
|
#define list_magic_chkbool(x, where) (list_magic_correct(x) || (list_magic_error(where, x), 1))
|
||
|
|
||
|
|
||
|
struct list_head {
|
||
|
void *magic1;
|
||
|
void *next;
|
||
|
void *prev;
|
||
|
void *magic2;
|
||
|
};
|
||
|
|
||
|
struct xlist_head {
|
||
|
void *magic1;
|
||
|
struct xlist_head *next;
|
||
|
struct xlist_head *prev;
|
||
|
void *magic2;
|
||
|
};
|
||
|
|
||
|
|
||
|
#define NULL_LIST_HEAD LISTMAGIC1, NULL, NULL, LISTMAGIC2
|
||
|
#define D_LIST_HEAD(x) LISTMAGIC1, &x, &x, LISTMAGIC2
|
||
|
#define LIST_HEAD(x) void *magic1; x *next; x *prev; void *magic2
|
||
|
#define LIST_SET_MAGIC(x) list_magic_set(*(x))
|
||
|
|
||
|
#endif /* LISTDEBUG */
|
||
|
|
||
|
#define INIT_LIST_HEAD(x) struct list_head x = { D_LIST_HEAD(x) }
|
||
|
|
||
|
#ifdef HAVE_TYPEOF
|
||
|
#define list_typeof(x) typeof(x)
|
||
|
#else
|
||
|
#define list_typeof(x) struct xlist_head *
|
||
|
#endif /* HAVE_TYPEOF */
|
||
|
|
||
|
|
||
|
#define init_list(x) \
|
||
|
do { \
|
||
|
list_magic_set(x); \
|
||
|
do_not_optimize_here_gcc_3_x(&(x)); /* antialiasing ;) */ \
|
||
|
(x).next = (x).prev = &(x); \
|
||
|
do_not_optimize_here_gcc_3_x(&(x)); \
|
||
|
} while (0)
|
||
|
|
||
|
|
||
|
#define list_empty(x) (list_magic_chkbool(x, "list_empty") && (x).next == &(x))
|
||
|
|
||
|
#define list_is_singleton(x) \
|
||
|
(list_magic_chkbool(x, "list_is_singleton") && (x).next == (x).prev)
|
||
|
|
||
|
#define list_has_prev(l,p) \
|
||
|
(list_magic_chkbool(l, "list_has_prev") && (p)->prev != (void *) &(l))
|
||
|
|
||
|
#define list_has_next(l,p) \
|
||
|
(list_magic_chkbool(l, "list_has_next") && (p)->next != (void *) &(l))
|
||
|
|
||
|
#define del_from_list(x) \
|
||
|
do { \
|
||
|
list_magic_check(x, "del_from_list"); \
|
||
|
do_not_optimize_here_gcc_2_7(x); \
|
||
|
((struct list_head *) (x)->next)->prev = (x)->prev; \
|
||
|
((struct list_head *) (x)->prev)->next = (x)->next; \
|
||
|
list_del_enforce(x); \
|
||
|
do_not_optimize_here_gcc_2_7(x); \
|
||
|
} while (0)
|
||
|
|
||
|
#define add_at_pos(p,x) \
|
||
|
do { \
|
||
|
list_magic_check(p, "add_at_pos"); \
|
||
|
list_magic_set(*(x)); \
|
||
|
do_not_optimize_here_gcc_2_7(p); \
|
||
|
(x)->next = (p)->next; \
|
||
|
(x)->prev = (p); \
|
||
|
(p)->next = (x); \
|
||
|
(x)->next->prev = (x); \
|
||
|
do_not_optimize_here_gcc_2_7(p); \
|
||
|
} while (0)
|
||
|
|
||
|
|
||
|
#define add_to_list(l,x) \
|
||
|
add_at_pos((list_typeof(x)) &(l), (list_typeof(x)) (x))
|
||
|
|
||
|
#define add_to_list_end(l,x) \
|
||
|
add_at_pos((list_typeof(x)) (l).prev, (list_typeof(x)) (x))
|
||
|
|
||
|
#define foreach(e,l) \
|
||
|
for ((e) = (l).next; \
|
||
|
(list_typeof(e)) (e) != (list_typeof(e)) &(l); \
|
||
|
(e) = (e)->next)
|
||
|
|
||
|
#define foreachback(e,l) \
|
||
|
for ((e) = (l).prev; \
|
||
|
(list_typeof(e)) (e) != (list_typeof(e)) &(l); \
|
||
|
(e) = (e)->prev)
|
||
|
|
||
|
#define foreachsafe(e, n, l) \
|
||
|
for ((e) = (l).next, (n) = (e)->next; \
|
||
|
(list_typeof(e)) (e) != (list_typeof(e)) &(l); \
|
||
|
(e) = (n), (n) = (e)->next)
|
||
|
|
||
|
#define foreachbacksafe(e, p, l) \
|
||
|
for ((e) = (l).prev, (p) = (e)->prev; \
|
||
|
(list_typeof(e)) (e) != (list_typeof(e)) &(l); \
|
||
|
(e) = (p), (p) = (e)->prev)
|
||
|
|
||
|
#define free_list(l) \
|
||
|
do { \
|
||
|
struct xlist_head *head, *next; \
|
||
|
\
|
||
|
list_magic_check(&(l), "free_list"); \
|
||
|
do_not_optimize_here_gcc_2_7(&l); \
|
||
|
foreach (head, (l)) do_not_optimize_here_gcc_3_x(head); /* AA */ \
|
||
|
foreachback (head, (l)) do_not_optimize_here_gcc_3_x(head); /* AA */ \
|
||
|
foreachsafe (head, next, l) { \
|
||
|
del_from_list(head); \
|
||
|
mem_free(head); \
|
||
|
} \
|
||
|
do_not_optimize_here_gcc_2_7(&l); \
|
||
|
} while (0)
|
||
|
|
||
|
static inline int
|
||
|
list_size(struct list_head *list)
|
||
|
{
|
||
|
struct list_head *item;
|
||
|
int size = 0;
|
||
|
|
||
|
foreach (item, *list)
|
||
|
size++;
|
||
|
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
#define move_to_top_of_list(list, item) do { \
|
||
|
if ((item) != (list).next) { \
|
||
|
del_from_list(item); \
|
||
|
add_to_list(list, item); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
|
||
|
#endif /* EL__UTIL_LISTS_H */
|