Browse Source

The konfd refactoring. Speed up. Not finished yet. The bugs a possible.

git-svn-id: https://klish.googlecode.com/svn/trunk@404 0eaa4687-2ee9-07dd-09d9-bcdd2d2dd5fb
Serj Kalichev 13 years ago
parent
commit
5441bdb1fa
15 changed files with 428 additions and 165 deletions
  1. 12 11
      Makefile.in
  2. 14 8
      bin/konfd.c
  3. 1 0
      konf/query.h
  4. 1 0
      konf/query/private.h
  5. 9 0
      konf/query/query.c
  6. 3 5
      konf/tree.h
  7. 3 3
      konf/tree/private.h
  8. 68 113
      konf/tree/tree.c
  9. 86 0
      lub/list.h
  10. 167 0
      lub/list/list.c
  11. 2 0
      lub/list/module.am
  12. 13 0
      lub/list/private.h
  13. 27 24
      lub/module.am
  14. 3 0
      lub/string.h
  15. 19 1
      lub/string/string_nocasecmp.c

File diff suppressed because it is too large
+ 12 - 11
Makefile.in


+ 14 - 8
bin/konfd.c

@@ -364,16 +364,18 @@ static char * process_query(int sock, konf_tree_t * conf, char *str)
 
 	case KONF_QUERY_OP_SET:
 		if (konf_query__get_unique(query)) {
-			if (konf_tree_find_conf(iconf,
-				konf_query__get_line(query), 0, 0)) {
-				ret = KONF_QUERY_OP_OK;
-				break;
-			}
-			konf_tree_del_pattern(iconf,
+			int exist = 0;
+			exist = konf_tree_del_pattern(iconf,
+				konf_query__get_line(query),
+				konf_query__get_unique(query),
 				konf_query__get_pattern(query),
 				konf_query__get_priority(query),
 				konf_query__get_seq(query),
 				konf_query__get_seq_num(query));
+			if (exist) {
+				ret = KONF_QUERY_OP_OK;
+				break;
+			}
 		}
 		tmpconf = konf_tree_new_conf(iconf,
 			konf_query__get_line(query), konf_query__get_priority(query),
@@ -389,8 +391,12 @@ static char * process_query(int sock, konf_tree_t * conf, char *str)
 
 	case KONF_QUERY_OP_UNSET:
 		konf_tree_del_pattern(iconf,
-			konf_query__get_pattern(query), konf_query__get_priority(query),
-			konf_query__get_seq(query), konf_query__get_seq_num(query));
+			NULL,
+			BOOL_TRUE,
+			konf_query__get_pattern(query),
+			konf_query__get_priority(query),
+			konf_query__get_seq(query),
+			konf_query__get_seq_num(query));
 		ret = KONF_QUERY_OP_OK;
 		break;
 

+ 1 - 0
konf/query.h

@@ -28,6 +28,7 @@ konf_query_op_t konf_query__get_op(konf_query_t *instance);
 char * konf_query__get_path(konf_query_t *instance);
 const char * konf_query__get_pattern(konf_query_t *instance);
 const char * konf_query__get_line(konf_query_t *instance);
+const char * konf_query__get_lower_line(konf_query_t *instance);
 unsigned short konf_query__get_priority(konf_query_t *instance);
 bool_t konf_query__get_splitter(konf_query_t *instance);
 bool_t konf_query__get_seq(konf_query_t *instance);

+ 1 - 0
konf/query/private.h

@@ -13,6 +13,7 @@ struct konf_query_s {
 	unsigned pwdc;
 	char **pwd;
 	char *line;
+	char *lower_line;
 	char *path;
 	bool_t splitter;
 	bool_t unique;

+ 9 - 0
konf/query/query.c

@@ -30,6 +30,7 @@ konf_query_t *konf_query_new(void)
 	this->pwdc = 0;
 	this->pwd = NULL;
 	this->line = NULL;
+	this->lower_line = NULL;
 	this->path = NULL;
 	this->splitter = BOOL_TRUE;
 	this->unique = BOOL_TRUE;
@@ -63,6 +64,7 @@ void konf_query_free(konf_query_t *this)
 
 	lub_string_free(this->pattern);
 	lub_string_free(this->line);
+	lub_string_free(this->lower_line);
 	lub_string_free(this->path);
 	if (this->pwdc > 0) {
 		for (i = 0; i < this->pwdc; i++)
@@ -161,6 +163,7 @@ int konf_query_parse(konf_query_t *this, int argc, char **argv)
 			break;
 		case 'l':
 			this->line = lub_string_dup(optarg);
+			this->lower_line = lub_string_tolower(optarg);
 			break;
 		case 'f':
 			this->path = lub_string_dup(optarg);
@@ -258,6 +261,12 @@ const char * konf_query__get_line(konf_query_t *this)
 	return this->line;
 }
 
+/*-------------------------------------------------------- */
+const char * konf_query__get_lower_line(konf_query_t *this)
+{
+	return this->lower_line;
+}
+
 /*-------------------------------------------------------- */
 unsigned short konf_query__get_priority(konf_query_t *this)
 {

+ 3 - 5
konf/tree.h

@@ -17,7 +17,7 @@ Use it to implement config in memory.
 #include <stdio.h>
 
 #include "lub/types.h"
-#include "lub/bintree.h"
+#include "lub/list.h"
 
 typedef struct konf_tree_s konf_tree_t;
 
@@ -31,10 +31,7 @@ typedef struct konf_tree_s konf_tree_t;
 /*-----------------
  * meta functions
  *----------------- */
-konf_tree_t *konf_tree_new(const char * line, unsigned short priority);
-int konf_tree_bt_compare(const void *clientnode, const void *clientkey);
-void konf_tree_bt_getkey(const void *clientnode, lub_bintree_key_t * key);
-size_t konf_tree_bt_offset(void);
+konf_tree_t *konf_tree_new(const char *line, unsigned short priority);
 
 /*-----------------
  * methods
@@ -48,6 +45,7 @@ konf_tree_t *konf_tree_new_conf(konf_tree_t * instance,
 konf_tree_t *konf_tree_find_conf(konf_tree_t * instance,
 	const char *line, unsigned short priority, unsigned short sequence);
 int konf_tree_del_pattern(konf_tree_t * instance,
+	const char *line, bool_t unique,
 	const char *pattern, unsigned short priority,
 	bool_t seq, unsigned short seq_num);
 

+ 3 - 3
konf/tree/private.h

@@ -6,15 +6,15 @@
 
 #include "konf/tree.h"
 #include "lub/types.h"
-#include "lub/bintree.h"
+#include "lub/list.h"
 
 /*---------------------------------------------------------
  * PRIVATE TYPES
  *--------------------------------------------------------- */
 struct konf_tree_s {
-	lub_bintree_t tree;
-	lub_bintree_node_t bt_node;
+	lub_list_t *list;
 	char *line;
+	char *lower_line;
 	unsigned short priority;
 	unsigned short seq_num;
 	unsigned short sub_num;

+ 68 - 113
konf/tree/tree.c

@@ -19,101 +19,69 @@
 /*---------------------------------------------------------
  * PRIVATE META FUNCTIONS
  *--------------------------------------------------------- */
-int konf_tree_bt_compare(const void *clientnode, const void *clientkey)
+static int konf_tree_compare(const void *first, const void *second)
 {
-	const konf_tree_t *this = clientnode;
-	unsigned short *pri = (unsigned short *)clientkey;
-	unsigned short *seq = (unsigned short *)clientkey + 1;
-	unsigned short *sub = (unsigned short *)clientkey + 2;
-	char *line = ((char *)clientkey + (3 * sizeof(unsigned short)));
+	const konf_tree_t *f = (const konf_tree_t *)first;
+	const konf_tree_t *s = (const konf_tree_t *)second;
 
 	/* Priority check */
-	if (this->priority != *pri)
-		return (this->priority - *pri);
+	if (f->priority != s->priority)
+		return (f->priority - s->priority);
 	/* Sequence check */
-	if (this->seq_num != *seq)
-		return (this->seq_num - *seq);
+	if (f->seq_num != s->seq_num)
+		return (f->seq_num - s->seq_num);
 	/* Sub-sequence check */
-	if (this->sub_num != *sub)
-		return (this->sub_num - *sub);
+	if (f->sub_num != s->sub_num)
+		return (f->sub_num - s->sub_num);
 	/* Line check */
-	return lub_string_nocasecmp(this->line, line);
-}
-
-/*-------------------------------------------------------- */
-static void konf_tree_key(lub_bintree_key_t * key,
-	unsigned short priority, unsigned short sequence,
-	unsigned short subseq, const char *text)
-{
-	unsigned short *pri = (unsigned short *)key;
-	unsigned short *seq = (unsigned short *)key + 1;
-	unsigned short *sub = (unsigned short *)key + 2;
-	char *line = ((char *)key + (3 * sizeof(unsigned short)));
-
-	/* fill out the opaque key */
-	*pri = priority;
-	*seq = sequence;
-	*sub = subseq;
-	strcpy(line, text);
-}
-
-/*-------------------------------------------------------- */
-void konf_tree_bt_getkey(const void *clientnode, lub_bintree_key_t * key)
-{
-	const konf_tree_t *this = clientnode;
-
-	konf_tree_key(key, this->priority, this->seq_num,
-		this->sub_num, this->line);
+	return strcmp(f->lower_line, s->lower_line);
 }
 
 /*---------------------------------------------------------
  * PRIVATE METHODS
  *--------------------------------------------------------- */
-static void
-konf_tree_init(konf_tree_t * this, const char *line, unsigned short priority)
+static void konf_tree_init(konf_tree_t * this, const char *line,
+	unsigned short priority)
 {
 	/* set up defaults */
 	this->line = lub_string_dup(line);
+	this->lower_line = lub_string_tolower(line);
 	this->priority = priority;
 	this->seq_num = 0;
 	this->sub_num = KONF_ENTRY_OK;
 	this->splitter = BOOL_TRUE;
 	this->depth = -1;
 
-	/* Be a good binary tree citizen */
-	lub_bintree_node_init(&this->bt_node);
-
-	/* initialise the tree of commands for this conf */
-	lub_bintree_init(&this->tree,
-		konf_tree_bt_offset(),
-		 konf_tree_bt_compare, konf_tree_bt_getkey);
+	/* initialise the list of commands for this conf */
+	this->list = lub_list_new(konf_tree_compare);
 }
 
 /*--------------------------------------------------------- */
 static void konf_tree_fini(konf_tree_t * this)
 {
-	konf_tree_t *conf;
+	lub_list_node_t *iter;
 
 	/* delete each conf held by this conf */
-	while ((conf = lub_bintree_findfirst(&this->tree))) {
+	
+	while ((iter = lub_list__get_head(this->list))) {
 		/* remove the conf from the tree */
-		lub_bintree_remove(&this->tree, conf);
+		lub_list_del(this->list, iter);
 		/* release the instance */
-		konf_tree_delete(conf);
+		konf_tree_delete((konf_tree_t *)lub_list_node__get_data(iter));
+		lub_list_node_free(iter);
 	}
+	lub_list_free(this->list);
 
 	/* free our memory */
 	lub_string_free(this->line);
 	this->line = NULL;
+	lub_string_free(this->lower_line);
+	this->lower_line = NULL;
 }
 
 /*---------------------------------------------------------
  * PUBLIC META FUNCTIONS
  *--------------------------------------------------------- */
-size_t konf_tree_bt_offset(void)
-{
-	return offsetof(konf_tree_t, bt_node);
-}
 
 /*--------------------------------------------------------- */
 konf_tree_t *konf_tree_new(const char *line, unsigned short priority)
@@ -137,11 +105,11 @@ void konf_tree_delete(konf_tree_t * this)
 
 /*--------------------------------------------------------- */
 void konf_tree_fprintf(konf_tree_t * this, FILE * stream,
-		const char *pattern, int top_depth,
-		bool_t seq, unsigned char prev_pri_hi)
+	const char *pattern, int top_depth,
+	bool_t seq, unsigned char prev_pri_hi)
 {
 	konf_tree_t *conf;
-	lub_bintree_iterator_t iter;
+	lub_list_node_t *iter;
 	unsigned char pri = 0;
 	regex_t regexp;
 
@@ -170,11 +138,9 @@ void konf_tree_fprintf(konf_tree_t * this, FILE * stream,
 		regcomp(&regexp, pattern, REG_EXTENDED | REG_ICASE);
 
 	/* iterate child elements */
-	if (!(conf = lub_bintree_findfirst(&this->tree)))
-		return;
-
-	for(lub_bintree_iterator_init(&iter, &this->tree, conf);
-		conf; conf = lub_bintree_iterator_next(&iter)) {
+	for(iter = lub_list__get_head(this->list);
+		iter; iter = lub_list_node__get_next(iter)) {
+		conf = (konf_tree_t *)lub_list_node__get_data(iter);
 		if (pattern && (0 != regexec(&regexp, conf->line, 0, NULL, 0)))
 			continue;
 		konf_tree_fprintf(conf, stream, NULL, top_depth, seq, pri);
@@ -189,44 +155,25 @@ static int normalize_seq(konf_tree_t * this, unsigned short priority)
 {
 	unsigned short cnt = 1;
 	konf_tree_t *conf = NULL;
-	lub_bintree_iterator_t iter;
+	lub_list_node_t *iter;
+	unsigned short cur_pri;
 
 	/* If tree is empty */
-	if (!(conf = lub_bintree_findfirst(&this->tree)))
+	if (!(iter = lub_list__get_head(this->list)))
 		return 0;
 
 	/* Iterate and set dirty */
-	lub_bintree_iterator_init(&iter, &this->tree, conf);
 	do {
-		unsigned short cur_pri = konf_tree__get_priority(conf);
-		if (cur_pri < priority)
-			continue;
-		if (konf_tree__get_seq_num(conf) == 0)
-			continue;
+		conf = (konf_tree_t *)lub_list_node__get_data(iter);
+		cur_pri = konf_tree__get_priority(conf);
 		if (cur_pri > priority)
 			break;
-		if (konf_tree__get_sub_num(conf) == KONF_ENTRY_OK)
-			konf_tree__set_sub_num(conf, KONF_ENTRY_DIRTY);
-	} while ((conf = lub_bintree_iterator_next(&iter)));
-
-	/* Iterate and renum */
-	conf = lub_bintree_findfirst(&this->tree);
-	lub_bintree_iterator_init(&iter, &this->tree, conf);
-	do {
-		unsigned short cur_pri = konf_tree__get_priority(conf);
 		if (cur_pri < priority)
 			continue;
 		if (konf_tree__get_seq_num(conf) == 0)
 			continue;
-		if (cur_pri > priority)
-			break;
-		if (konf_tree__get_sub_num(conf) == KONF_ENTRY_OK)
-			continue;
-		lub_bintree_remove(&this->tree, conf);
-		konf_tree__set_sub_num(conf, KONF_ENTRY_OK);
 		konf_tree__set_seq_num(conf, cnt++);
-		lub_bintree_insert(&this->tree, conf);
-	} while ((conf = lub_bintree_iterator_next(&iter)));
+	} while ((iter = lub_list_node__get_next(iter)));
 
 	return 0;
 }
@@ -248,11 +195,7 @@ konf_tree_t *konf_tree_new_conf(konf_tree_t * this,
 	}
 
 	/* Insert it into the binary tree for this conf */
-	if (-1 == lub_bintree_insert(&this->tree, newconf)) {
-		/* inserting a duplicate command is bad */
-		konf_tree_delete(newconf);
-		newconf = NULL;
-	}
+	lub_list_add(this->list, newconf);
 
 	if (seq)
 		normalize_seq(this, priority);
@@ -265,36 +208,44 @@ konf_tree_t *konf_tree_find_conf(konf_tree_t * this,
 	const char *line, unsigned short priority, unsigned short seq_num)
 {
 	konf_tree_t *conf;
-	lub_bintree_key_t key;
-	lub_bintree_iterator_t iter;
-
-	if ((0 != priority) && (0 != seq_num)) {
-		konf_tree_key(&key, priority, seq_num,
-			KONF_ENTRY_OK, line);
-		return lub_bintree_find(&this->tree, &key);
-	}
+	lub_list_node_t *iter;
+	int check_pri = 0;
 
-	/* If tree is empty */
-	if (!(conf = lub_bintree_findfirst(&this->tree)))
+	/* If list is empty */
+	if (!(iter = lub_list__get_head(this->list)))
 		return NULL;
 
+	if ((0 != priority) && (0 != seq_num))
+		check_pri = 1;
 	/* Iterate non-empty tree */
-	lub_bintree_iterator_init(&iter, &this->tree, conf);
 	do {
+		conf = (konf_tree_t *)lub_list_node__get_data(iter);
+		if (check_pri) {
+			if (priority > conf->priority)
+				continue;
+			if (priority < conf->priority)
+				break;
+			if (seq_num > conf->seq_num)
+				continue;
+			if (seq_num < conf->seq_num)
+				break;
+		}
 		if (0 == lub_string_nocasecmp(conf->line, line))
-			return conf;
-	} while ((conf = lub_bintree_iterator_next(&iter)));
+				return conf;
+	} while ((iter = lub_list_node__get_next(iter)));
 
 	return NULL;
 }
 
 /*--------------------------------------------------------- */
 int konf_tree_del_pattern(konf_tree_t *this,
+	const char *line, bool_t unique,
 	const char *pattern, unsigned short priority,
 	bool_t seq, unsigned short seq_num)
 {
+	int res = 0;
 	konf_tree_t *conf;
-	lub_bintree_iterator_t iter;
+	lub_list_node_t *iter;
 	regex_t regexp;
 	int del_cnt = 0; /* how many strings were deleted */
 
@@ -302,15 +253,15 @@ int konf_tree_del_pattern(konf_tree_t *this,
 		return -1;
 
 	/* Is tree empty? */
-	if (!(conf = lub_bintree_findfirst(&this->tree)))
+	if (!(iter = lub_list__get_head(this->list)))
 		return 0;
 
 	/* Compile regular expression */
 	regcomp(&regexp, pattern, REG_EXTENDED | REG_ICASE);
 
 	/* Iterate configuration tree */
-	lub_bintree_iterator_init(&iter, &this->tree, conf);
 	do {
+		conf = (konf_tree_t *)lub_list_node__get_data(iter);
 		if ((0 != priority) &&
 			(priority != conf->priority))
 			continue;
@@ -321,17 +272,21 @@ int konf_tree_del_pattern(konf_tree_t *this,
 			continue;
 		if (0 != regexec(&regexp, conf->line, 0, NULL, 0))
 			continue;
-		lub_bintree_remove(&this->tree, conf);
+		if (unique && line && !strcmp(conf->lower_line, line)) {
+			res++;
+			continue;
+		}
+		lub_list_del(this->list, iter);
 		konf_tree_delete(conf);
 		del_cnt++;
-	} while ((conf = lub_bintree_iterator_next(&iter)));
+	} while ((iter = lub_list_node__get_next(iter)));
 
 	regfree(&regexp);
 
 	if (seq && (del_cnt != 0))
 		normalize_seq(this, priority);
 
-	return 0;
+	return res;
 }
 
 /*--------------------------------------------------------- */

+ 86 - 0
lub/list.h

@@ -0,0 +1,86 @@
+#ifndef _lub_list_h
+#define _lub_list_h
+#include <stddef.h>
+
+/****************************************************************
+ * TYPE DEFINITIONS
+ **************************************************************** */
+
+typedef struct lub_list_node_s lub_list_node_t;
+
+/**
+ * This type defines a callback function which will compare two nodes
+ * with each other
+ *
+ * \param clientnode 	the client node to compare
+ * \param clientkey 	the key to compare with a node
+ *
+ * \return
+ *     <0 if clientnode  < clientkey;
+ *      0 if clientnode == clientkey;
+ *     >0 if clientnode  > clientkey
+ */
+typedef int lub_list_compare_fn(const void *first, const void *second);
+
+/**
+ * This type represents a list instance
+ */
+typedef struct lub_list_s lub_list_t;
+
+/**
+ * This is used to perform iterations of a list
+ */
+typedef struct lub_list_node_s lub_list_iterator_t;
+
+/****************************************************************
+ * LIST OPERATIONS
+ **************************************************************** */
+/**
+ * This operation initialises an instance of a list.
+ */
+extern lub_list_t *lub_list_new(lub_list_compare_fn compareFn);
+
+/**
+ * This operation is called to initialise a "clientnode" ready for
+ * insertion into a tree. This is only required once after the memory
+ * for a node has been allocated.
+ *
+ * \pre none
+ *
+ * \post The node is ready to be inserted into a tree.
+ */
+extern lub_list_node_t *lub_list_node_new(void *data);
+
+/*****************************************
+ * NODE MANIPULATION OPERATIONS
+ ***************************************** */
+/**
+ * This operation adds a client node to the specified tree.
+ *
+ * \pre The tree must be initialised
+ * \pre The clientnode must be initialised
+ * 
+ * \return
+ * 0 if the "clientnode" is added correctly to the tree.
+ * If another "clientnode" already exists in the tree with the same key, then
+ * -1 is returned, and the tree remains unchanged.
+ *
+ * \post If the bintree "node" is already part of a tree, then an
+ * assert will fire.
+ */
+
+void lub_list_free(lub_list_t *list);
+void lub_list_node_free(lub_list_node_t *node);
+inline lub_list_node_t *lub_list__get_head(lub_list_t *list);
+inline lub_list_node_t *lub_list__get_tail(lub_list_t *list);
+lub_list_node_t *lub_list_node__get_prev(lub_list_node_t *node);
+lub_list_node_t *lub_list_node__get_next(lub_list_node_t *node);
+void *lub_list_node__get_data(lub_list_node_t *node);
+lub_list_node_t *lub_list_iterator_init(lub_list_t *list);
+lub_list_node_t *lub_list_iterator_next(lub_list_node_t *node);
+lub_list_node_t *lub_list_iterator_prev(lub_list_node_t *node);
+lub_list_node_t *lub_list_add(lub_list_t *list, void *data);
+void lub_list_del(lub_list_t *list, lub_list_node_t *node);
+
+#endif				/* _lub_list_h */
+

+ 167 - 0
lub/list/list.c

@@ -0,0 +1,167 @@
+#include <stdlib.h>
+#include <assert.h>
+
+#include "private.h"
+
+/*--------------------------------------------------------- */
+static inline void lub_list_init(lub_list_t * this,
+	lub_list_compare_fn compareFn)
+{
+	this->head = NULL;
+	this->compareFn = compareFn;
+}
+
+/*--------------------------------------------------------- */
+lub_list_t *lub_list_new(lub_list_compare_fn compareFn)
+{
+	lub_list_t *this;
+
+	this = malloc(sizeof(*this));
+	assert(this);
+	lub_list_init(this, compareFn);
+
+	return this;
+}
+
+/*--------------------------------------------------------- */
+void inline lub_list_free(lub_list_t *this)
+{
+	free(this);
+}
+
+/*--------------------------------------------------------- */
+inline lub_list_node_t *lub_list__get_head(lub_list_t *this)
+{
+	return this->head;
+}
+
+/*--------------------------------------------------------- */
+inline lub_list_node_t *lub_list__get_tail(lub_list_t *this)
+{
+	return this->tail;
+}
+
+/*--------------------------------------------------------- */
+static inline void lub_list_node_init(lub_list_node_t *this,
+	void *data)
+{
+	this->prev = this->next = NULL;
+	this->data = data;
+}
+
+/*--------------------------------------------------------- */
+lub_list_node_t *lub_list_node_new(void *data)
+{
+	lub_list_node_t *this;
+
+	this = malloc(sizeof(*this));
+	assert(this);
+	lub_list_node_init(this, data);
+
+	return this;
+}
+
+/*--------------------------------------------------------- */
+inline lub_list_node_t *lub_list_iterator_init(lub_list_t *this)
+{
+	return this->head;
+}
+
+/*--------------------------------------------------------- */
+inline lub_list_node_t *lub_list_iterator_next(lub_list_node_t *this)
+{
+	return lub_list_node__get_next(this);
+}
+
+/*--------------------------------------------------------- */
+inline lub_list_node_t *lub_list_iterator_prev(lub_list_node_t *this)
+{
+	return lub_list_node__get_prev(this);
+}
+
+/*--------------------------------------------------------- */
+void inline lub_list_node_free(lub_list_node_t *this)
+{
+	free(this);
+}
+
+/*--------------------------------------------------------- */
+inline lub_list_node_t *lub_list_node__get_prev(lub_list_node_t *this)
+{
+	return this->prev;
+}
+
+/*--------------------------------------------------------- */
+inline lub_list_node_t *lub_list_node__get_next(lub_list_node_t *this)
+{
+	return this->next;
+}
+
+/*--------------------------------------------------------- */
+inline void *lub_list_node__get_data(lub_list_node_t *this)
+{
+	return this->data;
+}
+
+/*--------------------------------------------------------- */
+lub_list_node_t *lub_list_add(lub_list_t *this, void *data)
+{
+	lub_list_node_t *node = lub_list_node_new(data);
+	lub_list_node_t *iter;
+
+	/* Empty list */
+	if (!this->head) {
+		this->head = node;
+		this->tail = node;
+		return node;
+	}
+
+	/* Not sorted list. Add to the tail. */
+	if (!this->compareFn) {
+		node->prev = this->tail;
+		node->next = NULL;
+		this->tail->next = node;
+		this->tail = node;
+		return node;
+	}
+
+	/* Sorted list */
+	iter = this->tail;
+	while (iter) {
+		if (this->compareFn(node->data, iter->data) >= 0) {
+			node->next = iter->next;
+			node->prev = iter;
+			iter->next = node;
+			if (node->next)
+				node->next->prev = node;
+			break;
+		}
+		iter = iter->prev;
+	}
+	/* Insert node into the list head */
+	if (!iter) {
+		node->next = this->head;
+		node->prev = NULL;
+		this->head->prev = node;
+		this->head = node;
+	}
+	if (!node->next)
+		this->tail = node;
+
+	return node;
+}
+
+/*--------------------------------------------------------- */
+void lub_list_del(lub_list_t *this, lub_list_node_t *node)
+{
+	if (node->prev)
+		node->prev->next = node->next;
+	else
+		this->head = node->next;
+	if (node->next)
+		node->next->prev = node->prev;
+	else
+		this->tail = node->prev;
+}
+
+/*--------------------------------------------------------- */

+ 2 - 0
lub/list/module.am

@@ -0,0 +1,2 @@
+## Process this file with automake to produce Makefile.in
+liblub_la_SOURCES += lub/list/list.c

+ 13 - 0
lub/list/private.h

@@ -0,0 +1,13 @@
+#include "lub/list.h"
+
+struct lub_list_node_s {
+	lub_list_node_t *prev;
+	lub_list_node_t *next;
+	void *data;
+};
+
+struct lub_list_s {
+	lub_list_node_t *head;
+	lub_list_node_t *tail;
+	lub_list_compare_fn *compareFn;
+};

+ 27 - 24
lub/module.am

@@ -3,37 +3,40 @@ lib_LTLIBRARIES         += liblub.la
 liblub_la_SOURCES        =
 liblub_la_LIBADD         = -lpthread
 
-nobase_include_HEADERS  +=  \
-    lub/argv.h              \
-    lub/bintree.h           \
-    lub/blockpool.h         \
-    lub/ctype.h             \
-    lub/dblockpool.h        \
-    lub/c_decl.h            \
-    lub/dump.h              \
-    lub/heap.h              \
-    lub/partition.h         \
-    lub/string.h            \
-    lub/size_fmt.h          \
-    lub/test.h              \
-    lub/types.h             \
+nobase_include_HEADERS += \
+    lub/argv.h \
+    lub/bintree.h \
+    lub/list.h \
+    lub/blockpool.h \
+    lub/ctype.h \
+    lub/dblockpool.h \
+    lub/c_decl.h \
+    lub/dump.h \
+    lub/heap.h \
+    lub/partition.h \
+    lub/string.h \
+    lub/size_fmt.h \
+    lub/test.h \
+    lub/types.h \
     lub/system.h
 
-EXTRA_DIST             +=   \
-    lub/argv/module.am      \
-    lub/bintree/module.am   \
+EXTRA_DIST +=   \
+    lub/argv/module.am \
+    lub/bintree/module.am \
+    lub/list/module.am \
     lub/blockpool/module.am \
-    lub/ctype/module.am     \
-    lub/dblockpool/module.am\
-    lub/dump/module.am      \
-    lub/heap/module.am      \
-    lub/string/module.am    \
-    lub/test/module.am      \
-    lub/system/module.am    \
+    lub/ctype/module.am \
+    lub/dblockpool/module.am \
+    lub/dump/module.am \
+    lub/heap/module.am \
+    lub/string/module.am \
+    lub/test/module.am \
+    lub/system/module.am \
     lub/README
 
 include $(top_srcdir)/lub/argv/module.am
 include $(top_srcdir)/lub/bintree/module.am
+include $(top_srcdir)/lub/list/module.am
 include $(top_srcdir)/lub/blockpool/module.am
 include $(top_srcdir)/lub/ctype/module.am
 include $(top_srcdir)/lub/dblockpool/module.am

+ 3 - 0
lub/string.h

@@ -247,6 +247,9 @@ char *lub_string_decode(const char *string);
  */
 char *lub_string_encode(const char *string, const char *escape_chars);
 
+char *lub_string_tolower(const char *str);
+
+
 _END_C_DECL
 #endif				/* _lub_string_h */
 /** @} */

+ 19 - 1
lub/string/string_nocasecmp.c

@@ -1,10 +1,13 @@
 /*
  * string_nocasecmp.c
  */
-#include "private.h"
+#include <string.h>
+#include <ctype.h>
 
+#include "private.h"
 #include "lub/ctype.h"
 
+
 /*--------------------------------------------------------- */
 int lub_string_nocasecmp(const char *cs, const char *ct)
 {
@@ -30,4 +33,19 @@ int lub_string_nocasecmp(const char *cs, const char *ct)
 	return result;
 }
 
+/*--------------------------------------------------------- */
+char *lub_string_tolower(const char *str)
+{
+	char *tmp = strdup(str);
+	char *p = tmp;
+
+	while (*p) {
+		*p = tolower(*p);
+		p++;
+	}
+
+	return tmp;
+}
+
+
 /*--------------------------------------------------------- */

Some files were not shown because too many files changed in this diff