From: Karel Zak Date: Tue, 5 Jan 2010 13:58:16 +0000 (+0100) Subject: libmount: add list routines and generic iterator X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=efab4b61572516f4c7579e345165e0094c1a2450;p=util-linux libmount: add list routines and generic iterator Signed-off-by: Karel Zak --- diff --git a/shlibs/mount/src/Makefile.am b/shlibs/mount/src/Makefile.am index e9c7cc92..6f2b9502 100644 --- a/shlibs/mount/src/Makefile.am +++ b/shlibs/mount/src/Makefile.am @@ -12,7 +12,7 @@ usrlib_exec_LTLIBRARIES = libmount.la libmount_la_SOURCES = $(mountinc_HEADERS) nodist_libmount_la_SOURCES = mount.h version.c utils.c test.c init.c cache.c \ - optstr.c \ + optstr.c iter.c list.h \ $(top_srcdir)/lib/canonicalize.c libmount_la_LIBADD = $(ul_libblkid_la) diff --git a/shlibs/mount/src/iter.c b/shlibs/mount/src/iter.c new file mode 100644 index 00000000..d64f2d40 --- /dev/null +++ b/shlibs/mount/src/iter.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Karel Zak + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include +#include +#include + +#include "mountP.h" + +/** + * mnt_new_iter: + * @direction: MNT_INTER_{FOR,BACK}WARD direction + * + * Returns newly allocated generic libmount iterator. + */ +mnt_iter *mnt_new_iter(int direction) +{ + mnt_iter *itr = calloc(1, sizeof(struct _mnt_iter)); + if (!itr) + return NULL; + itr->direction = direction; + return itr; +} + +/** + * mnt_free_iter: + * @itr: iterator pointer + * + * Deallocates iterator. + */ +void mnt_free_iter(mnt_iter *itr) +{ + free(itr); +} + +/** + * mnt_reset_iter: + * @itr: iterator pointer + * @direction: MNT_INTER_{FOR,BACK}WARD iterator direction + * + * Resets iterator. + */ +void mnt_reset_iter(mnt_iter *itr, int direction) +{ + assert(itr); + + if (itr) { + memset(itr, 0, sizeof(struct _mnt_iter)); + itr->direction = direction; + } +} diff --git a/shlibs/mount/src/list.h b/shlibs/mount/src/list.h new file mode 100644 index 00000000..9f8b88a2 --- /dev/null +++ b/shlibs/mount/src/list.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2008 Karel Zak + * Copyright (C) 1999-2008 by Theodore Ts'o + * + * (based on list.h from e2fsprogs) + */ + +#if !defined(_LIBMOUNT_LIST_H) && !defined(LIST_HEAD) +#define _LIBMOUNT_LIST_H + +/* TODO: use AC_C_INLINE */ +#ifdef __GNUC__ +#define _INLINE_ static __inline__ +#else /* For Watcom C */ +#define _INLINE_ static inline +#endif + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +_INLINE_ void __list_add(struct list_head * add, + struct list_head * prev, + struct list_head * next) +{ + next->prev = add; + add->next = next; + add->prev = prev; + prev->next = add; +} + +/** + * list_add - add a new entry + * @add: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +_INLINE_ void list_add(struct list_head *add, struct list_head *head) +{ + __list_add(add, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @add: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +_INLINE_ void list_add_tail(struct list_head *add, struct list_head *head) +{ + __list_add(add, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +_INLINE_ void __list_del(struct list_head * prev, + struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * + * list_empty() on @entry does not return true after this, @entry is + * in an undefined state. + */ +_INLINE_ void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +_INLINE_ void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +_INLINE_ int list_empty(struct list_head *head) +{ + return head->next == head; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +_INLINE_ void list_splice(struct list_head *list, struct list_head *head) +{ + struct list_head *first = list->next; + + if (first != list) { + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +/** + * list_for_each - iterate over elements in a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_safe - iterate over elements in a list, but don't dereference + * pos after the body is done (in case it is freed) + * @pos: the &struct list_head to use as a loop counter. + * @pnext: the &struct list_head to use as a pointer to the next item. + * @head: the head for your list (not included in iteration). + */ +#define list_for_each_safe(pos, pnext, head) \ + for (pos = (head)->next, pnext = pos->next; pos != (head); \ + pos = pnext, pnext = pos->next) + +#undef _INLINE_ + +#endif /* __LIBFSPROBE_LIST_H__ */ diff --git a/shlibs/mount/src/mount.h.in b/shlibs/mount/src/mount.h.in index 3426729b..696c2940 100644 --- a/shlibs/mount/src/mount.h.in +++ b/shlibs/mount/src/mount.h.in @@ -34,6 +34,13 @@ extern "C" { */ typedef struct _mnt_cache mnt_cache; +/** + * mnt_iter + * + * Generic iterator (stores state about lists) + */ +typedef struct _mnt_iter mnt_iter; + /* version.c */ extern int mnt_parse_version_string(const char *ver_string); extern int mnt_get_library_version(const char **ver_string); @@ -67,6 +74,17 @@ extern int mnt_optstr_set_option(char **optstr, const char *name, const char *value); extern int mnt_optstr_remove_option(char **optstr, const char *name); + +/* iter.c */ +enum { + + MNT_ITER_FORWARD = 0, + MNT_ITER_BACKWARD +}; +extern mnt_iter *mnt_new_iter(int direction); +extern void mnt_free_iter(mnt_iter *mi); +extern void mnt_reset_iter(mnt_iter *mi, int direction); + #ifdef __cplusplus } #endif diff --git a/shlibs/mount/src/mountP.h b/shlibs/mount/src/mountP.h index 74db2556..ef3c1a66 100644 --- a/shlibs/mount/src/mountP.h +++ b/shlibs/mount/src/mountP.h @@ -11,7 +11,9 @@ #define _LIBMOUNT_PRIVATE_H #include + #include "mount.h" +#include "list.h" /* features */ #define CONFIG_CDROM_NOMEDIUM_RETRIES 5 @@ -69,4 +71,31 @@ extern char *strnchr(const char *s, size_t maxlen, int c); extern char *mnt_get_username(const uid_t uid); extern char *mnt_strconcat3(char *s, const char *t, const char *u); + +/* + * Generic iterator + */ +struct _mnt_iter { + struct list_head *p; /* current position */ + struct list_head *head; /* start position */ + int direction; /* MNT_ITER_{FOR,BACK}WARD */ +}; + +#define IS_ITER_FORWARD(_i) ((_i)->direction == MNT_ITER_FORWARD) +#define IS_ITER_BACKWARD(_i) ((_i)->direction == MNT_ITER_BACKWARD) + +#define MNT_ITER_INIT(itr, list) \ + do { \ + (itr)->p = IS_ITER_FORWARD(itr) ? \ + (list)->next : (list)->prev; \ + (itr)->head = (list); \ + } while(0) + +#define MNT_ITER_ITERATE(itr, res, restype, member) \ + do { \ + res = list_entry((itr)->p, restype, member); \ + (itr)->p = IS_ITER_FORWARD(itr) ? \ + (itr)->p->next : (itr)->p->prev; \ + } while(0) + #endif