Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | #ifndef _LISTHELP_H |
| 2 | #define _LISTHELP_H |
| 3 | #include <linux/config.h> |
| 4 | #include <linux/list.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5 | |
| 6 | /* Header to do more comprehensive job than linux/list.h; assume list |
| 7 | is first entry in structure. */ |
| 8 | |
| 9 | /* Return pointer to first true entry, if any, or NULL. A macro |
| 10 | required to allow inlining of cmpfn. */ |
| 11 | #define LIST_FIND(head, cmpfn, type, args...) \ |
| 12 | ({ \ |
| 13 | const struct list_head *__i, *__j = NULL; \ |
| 14 | \ |
| 15 | ASSERT_READ_LOCK(head); \ |
| 16 | list_for_each(__i, (head)) \ |
| 17 | if (cmpfn((const type)__i , ## args)) { \ |
| 18 | __j = __i; \ |
| 19 | break; \ |
| 20 | } \ |
| 21 | (type)__j; \ |
| 22 | }) |
| 23 | |
| 24 | #define LIST_FIND_W(head, cmpfn, type, args...) \ |
| 25 | ({ \ |
| 26 | const struct list_head *__i, *__j = NULL; \ |
| 27 | \ |
| 28 | ASSERT_WRITE_LOCK(head); \ |
| 29 | list_for_each(__i, (head)) \ |
| 30 | if (cmpfn((type)__i , ## args)) { \ |
| 31 | __j = __i; \ |
| 32 | break; \ |
| 33 | } \ |
| 34 | (type)__j; \ |
| 35 | }) |
| 36 | |
| 37 | /* Just like LIST_FIND but we search backwards */ |
| 38 | #define LIST_FIND_B(head, cmpfn, type, args...) \ |
| 39 | ({ \ |
| 40 | const struct list_head *__i, *__j = NULL; \ |
| 41 | \ |
| 42 | ASSERT_READ_LOCK(head); \ |
| 43 | list_for_each_prev(__i, (head)) \ |
| 44 | if (cmpfn((const type)__i , ## args)) { \ |
| 45 | __j = __i; \ |
| 46 | break; \ |
| 47 | } \ |
| 48 | (type)__j; \ |
| 49 | }) |
| 50 | |
| 51 | static inline int |
| 52 | __list_cmp_same(const void *p1, const void *p2) { return p1 == p2; } |
| 53 | |
| 54 | /* Is this entry in the list? */ |
| 55 | static inline int |
| 56 | list_inlist(struct list_head *head, const void *entry) |
| 57 | { |
| 58 | return LIST_FIND(head, __list_cmp_same, void *, entry) != NULL; |
| 59 | } |
| 60 | |
| 61 | /* Delete from list. */ |
| 62 | #ifdef CONFIG_NETFILTER_DEBUG |
| 63 | #define LIST_DELETE(head, oldentry) \ |
| 64 | do { \ |
| 65 | ASSERT_WRITE_LOCK(head); \ |
| 66 | if (!list_inlist(head, oldentry)) \ |
| 67 | printk("LIST_DELETE: %s:%u `%s'(%p) not in %s.\n", \ |
| 68 | __FILE__, __LINE__, #oldentry, oldentry, #head); \ |
| 69 | else list_del((struct list_head *)oldentry); \ |
| 70 | } while(0) |
| 71 | #else |
| 72 | #define LIST_DELETE(head, oldentry) list_del((struct list_head *)oldentry) |
| 73 | #endif |
| 74 | |
| 75 | /* Append. */ |
| 76 | static inline void |
| 77 | list_append(struct list_head *head, void *new) |
| 78 | { |
| 79 | ASSERT_WRITE_LOCK(head); |
| 80 | list_add((new), (head)->prev); |
| 81 | } |
| 82 | |
| 83 | /* Prepend. */ |
| 84 | static inline void |
| 85 | list_prepend(struct list_head *head, void *new) |
| 86 | { |
| 87 | ASSERT_WRITE_LOCK(head); |
| 88 | list_add(new, head); |
| 89 | } |
| 90 | |
| 91 | /* Insert according to ordering function; insert before first true. */ |
| 92 | #define LIST_INSERT(head, new, cmpfn) \ |
| 93 | do { \ |
| 94 | struct list_head *__i; \ |
| 95 | ASSERT_WRITE_LOCK(head); \ |
| 96 | list_for_each(__i, (head)) \ |
| 97 | if ((new), (typeof (new))__i) \ |
| 98 | break; \ |
| 99 | list_add((struct list_head *)(new), __i->prev); \ |
| 100 | } while(0) |
| 101 | |
| 102 | /* If the field after the list_head is a nul-terminated string, you |
| 103 | can use these functions. */ |
| 104 | static inline int __list_cmp_name(const void *i, const char *name) |
| 105 | { |
| 106 | return strcmp(name, i+sizeof(struct list_head)) == 0; |
| 107 | } |
| 108 | |
| 109 | /* Returns false if same name already in list, otherwise does insert. */ |
| 110 | static inline int |
| 111 | list_named_insert(struct list_head *head, void *new) |
| 112 | { |
| 113 | if (LIST_FIND(head, __list_cmp_name, void *, |
| 114 | new + sizeof(struct list_head))) |
| 115 | return 0; |
| 116 | list_prepend(head, new); |
| 117 | return 1; |
| 118 | } |
| 119 | |
| 120 | /* Find this named element in the list. */ |
| 121 | #define list_named_find(head, name) \ |
| 122 | LIST_FIND(head, __list_cmp_name, void *, name) |
| 123 | |
| 124 | #endif /*_LISTHELP_H*/ |