File:  [ELWIX - Embedded LightWeight unIX -] / gpl / axl / src / axl_list.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 12:50:03 2012 UTC (12 years, 4 months ago) by misho
Branches: axl, MAIN
CVS tags: HEAD, AXL0_6_7
version 0.6.7

    1: /*
    2:  *  LibAxl:  Another XML library
    3:  *  Copyright (C) 2006 Advanced Software Production Line, S.L.
    4:  *
    5:  *  This program is free software; you can redistribute it and/or
    6:  *  modify it under the terms of the GNU Lesser General Public License
    7:  *  as published by the Free Software Foundation; either version 2.1 of
    8:  *  the License, or (at your option) any later version.
    9:  *
   10:  *  This program is distributed in the hope that it will be useful,
   11:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
   12:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
   13:  *  GNU Lesser General Public License for more details.
   14:  *
   15:  *  You should have received a copy of the GNU Lesser General Public
   16:  *  License along with this program; if not, write to the Free
   17:  *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:  *  02111-1307 USA
   19:  *  
   20:  *  You may find a copy of the license under this software is released
   21:  *  at COPYING file. This is LGPL software: you are welcome to
   22:  *  develop proprietary applications using this library without any
   23:  *  royalty or fee but returning back any change, improvement or
   24:  *  addition in the form of source code, project image, documentation
   25:  *  patches, etc. 
   26:  *
   27:  *  For commercial support on build XML enabled solutions contact us:
   28:  *          
   29:  *      Postal address:
   30:  *         Advanced Software Production Line, S.L.
   31:  *         Edificio Alius A, Oficina 102,
   32:  *         C/ Antonio Suarez Nº 10,
   33:  *         Alcalá de Henares 28802 Madrid
   34:  *         Spain
   35:  *
   36:  *      Email address:
   37:  *         info@aspl.es - http://www.aspl.es/xml
   38:  */
   39: 
   40: #include <axl_decl.h>
   41: #include <axl_list.h>
   42: #include <axl_log.h>
   43: #include <axl_stream.h>
   44: 
   45: #define LOG_DOMAIN "axl-list"
   46: 
   47: typedef struct _axlListNode axlListNode;
   48: 
   49: struct _axlList {
   50: 	/* functions used by the list to properly order elements
   51: 	 * inside it and how they are destroyed */
   52: 	axlEqualFunc     are_equal;
   53: 	axlDestroyFunc   destroy_data;
   54: 
   55: 	/* pointers to the list content */
   56: 	axlListNode    * first_node;
   57: 	axlListNode    * last_node;
   58: 
   59: 	/* list length */
   60: 	int              length;
   61: 
   62: 	/* memory management functions */
   63: 	axlListNode   ** preallocated;
   64: 	int              available;
   65: 	int              allocated;
   66: };
   67: 
   68: struct _axlListNode {
   69: 	axlListNode * previous;
   70: 	axlListNode * next;
   71: 	axlPointer    data;
   72: };
   73: 
   74: struct _axlListCursor {
   75: 	axlList     * list;
   76: 	axlListNode * current;
   77: };
   78: 
   79: /**
   80:  * \defgroup axl_list_module Axl List: A configurable double-linked list used across the library.
   81:  */
   82: 
   83: /** 
   84:  * \addtogroup axl_list_module
   85:  * @{
   86:  */
   87: 
   88: /** 
   89:  * @internal
   90:  * 
   91:  * Internal are equal handler implementation for the axl list module
   92:  * that always return 0.
   93:  */
   94: int __axl_list_always_true (axlPointer a, axlPointer b)
   95: {
   96: 	return 0;
   97: }
   98: 
   99: /** 
  100:  * @internal
  101:  *
  102:  * Preallocates nodes to be used to store data on the lists.
  103:  * 
  104:  * @param list The list where the preallocation operation will be
  105:  * performed.
  106:  */
  107: void  __axl_list_allocate_nodes (axlList * list)
  108: {
  109: 	int              iterator;
  110: 	axlListNode   ** temp;
  111: 	int              available;
  112: 
  113: 	list->available     = 1;
  114: 	list->allocated    += list->available;
  115: 
  116: 	/* allocate enough memory to hold all nodes already
  117: 	 * allocated */
  118: 	if (list->preallocated == NULL) {
  119: 		list->preallocated  = axl_new (axlListNode *, list->allocated);
  120: 		if (list->preallocated == NULL) {
  121: 			/* reduce noddes available */
  122: 			list->available = 0;
  123: 			list->allocated--;
  124: 			return;
  125: 		}
  126: 	} else {
  127: 		/* realloc for the list */
  128: 		temp                = list->preallocated;
  129: 		list->preallocated  = realloc (list->preallocated, (sizeof (axlListNode *)) * list->allocated);
  130: 
  131: 		/* check alloc operation */
  132: 		if (list->preallocated == NULL) {
  133: 			/* alloc failed, restore to previous pointer */
  134: 			list->preallocated = temp;
  135: 
  136: 			/* reduce noddes available */
  137: 			list->available = 0;
  138: 			list->allocated--;
  139: 
  140: 			return;
  141: 		}
  142: 	} /* end */
  143: 
  144: 	/* reached this point, alloc operation worked */
  145: 
  146: 	/* allocate a node for each available position */
  147: 	available = list->available;
  148: 	for (iterator = 0; iterator < list->available; iterator++) {
  149: 		/* alloc node */
  150: 		list->preallocated[iterator] = axl_new (axlListNode, 1);
  151: 
  152: 		/* check alloc operation */
  153: 		if (list->preallocated[iterator] == NULL) {
  154: 			available--;
  155: 		} /* end if */
  156: 	} /* end if */
  157: 
  158: 	/* update list of available nodes */
  159: 	list->available = available;
  160: 	
  161: 	return;
  162: }
  163: 
  164: /** 
  165:  * @internal
  166:  * 
  167:  * Disposes the node provided, reusing on the next operation
  168:  * requested.
  169:  */
  170: void __axl_list_dispose_node (axlList * list, axlListNode * node)
  171: {
  172: 	/* store the node to be usable again */
  173: 	list->preallocated [list->available] = node;
  174: 	
  175: 	/* increase current available nodes */
  176: 	list->available++;
  177: 	
  178: 	return;
  179: }
  180: 
  181: /** 
  182:  * @internal
  183:  *
  184:  * Returns a reference to an list node to be used.
  185:  */
  186: axlListNode * __axl_list_get_next_node_available (axlList * list)
  187: {
  188: 	axlListNode * node;
  189: 
  190: 	/* check that there are nodes available */
  191: 	if (list->available == 0) {
  192: 		/* alloc nodes */
  193: 		__axl_list_allocate_nodes (list);
  194: 
  195: 		/* check if there are available nodes */
  196: 		if (list->available == 0)
  197: 			return NULL;
  198: 	} /* end if */
  199: 	
  200: 	/* get the next node available */
  201: 	node = list->preallocated[list->available - 1];
  202: 	list->available--;
  203: 
  204: 	/* clean node */
  205: 	node->next     = NULL;
  206: 	node->previous = NULL;
  207: 	node->data     = NULL;
  208: 		
  209: 	return node;
  210: }
  211: 
  212: 
  213: /** 
  214:  * @brief Creates a new \ref axlList, using provided handlers.
  215:  *
  216:  * An \ref axlList is a double linked list, with the hability to
  217:  * recognize elements inside its list by providing the \ref
  218:  * axlEqualFunc "are_equal" function and the ability to release
  219:  * memory allocated by the data stored by providing a \ref
  220:  * axlDestroyFunc "destroy_data" handler. 
  221:  *
  222:  * The destroy handler is a optional value. If not provided, any
  223:  * automatic deallocation function will not provided. 
  224:  *
  225:  * The "are equal" handler is not optinal. You must provide it to make
  226:  * the list work. In the case you don't like a ordering feature you
  227:  * can provide an are equal that just return 0 when elements are equal
  228:  * and always -1 for the rest of the cases if element should be
  229:  * appended or 1 if the element should be prepended.
  230:  *
  231:  * The list is not prepared to be managed at the same type by several
  232:  * threads. If the list is created and then used by several threads it
  233:  * will work properly. However, if several threads add and removes
  234:  * elements at the same time rainy days will come and you'll get funny
  235:  * behaviours.
  236:  *
  237:  * To create the list you must provide two function that performs some
  238:  * minimal functions required by the list o properly order the data
  239:  * inside the list and how this data is deallocated (this is
  240:  * optional).
  241:  * 
  242:  * For example, to create a list that will hold strings dinamically
  243:  * allocated you can use:
  244:  * \code
  245:  * axlList * list = axl_list_new (axl_list_equal_string, axl_free);
  246:  * \endcode
  247:  *
  248:  * For a list that will holds integer values you can use: \ref
  249:  * axl_list_equal_int. 
  250:  * 
  251:  * Previous list will cause all strings inside to be deallocated once
  252:  * called to \ref axl_list_free. If you don't like this, do not
  253:  * provide the deallocation function.
  254:  *
  255:  * You can always use the following function to make the list to allways
  256:  * add all data at the end of the list: \ref axl_list_always_return_1,
  257:  * which, as its names indicates, allways return 1, causing the item
  258:  * to be added at the end of the list. See \ref axlEqualFunc
  259:  * documentation to know more about creating ordenation functions.
  260:  *
  261:  * Now you have your list created, you can use the following functions
  262:  * to add items:
  263:  *
  264:  *  - \ref axl_list_add
  265:  *  - \ref axl_list_add_at
  266:  *  - \ref axl_list_prepend
  267:  *  - \ref axl_list_append
  268:  *
  269:  * Once you have inserted some data, you can use the following piece
  270:  * of code to perform an iteration:
  271:  *
  272:  * \code
  273:  * int iterator = 0;
  274:  * while (iterator < axl_list_length (list)) {
  275:  *     // get the data at the given position 
  276:  *     data = axl_list_get_nth (list, iterator);
  277:  *
  278:  *     // update the iterator 
  279:  *     iterator++;
  280:  * }
  281:  * \endcode
  282:  *
  283:  * However, it is preferred to use the \ref axlListCursor, which is
  284:  * far more efficient. See the following function to get more
  285:  * information: \ref axl_list_cursor_new.
  286:  *
  287:  * In general, if you are going to perform a lookup for a single item
  288:  * you can use \ref axl_list_lookup (by providing a handler) or \ref
  289:  * axl_list_get_nth if you know the position.
  290:  *
  291:  * 
  292:  * @param are_equal The equal function to be used by the list to find
  293:  * and order elements inside the list.
  294:  *
  295:  * @param destroy_data An optional handler to destroy nodes in the
  296:  * case the list is unrefered.
  297:  * 
  298:  * @return A newly allocated list, that must be destroy by calling to
  299:  * \ref axl_list_free.
  300:  */
  301: axlList * axl_list_new    (axlEqualFunc are_equal, axlDestroyFunc destroy_data)
  302: {
  303: 	axlList * result;
  304: 
  305: 	axl_return_val_if_fail (are_equal, NULL);
  306: 
  307: 	/* alloc node */
  308: 	result               = axl_new (axlList, 1);
  309: 	/* check alloc operation */
  310: 	if (result == NULL)
  311: 		return NULL;
  312: 	result->are_equal    = are_equal;
  313: 	result->destroy_data = destroy_data;
  314: 
  315: 	/* preallocate memory for nodes */
  316: 	/* __axl_list_allocate_nodes (result); */
  317: 
  318: 	return result;
  319: }
  320: 
  321: /**
  322:  * @brief Allows to reconfigure the destroy function to be used on
  323:  * this list. This function can be useful to disable the destroy
  324:  * function associated to the list. 
  325:  *
  326:  * @param list The list to reconfigure or disable (NULL) the destroy function.
  327:  *
  328:  * @param destroy_data The reference to the destroy function to be
  329:  * used or NULL to disable it.
  330:  */
  331: void       axl_list_set_destroy_func (axlList * list, axlDestroyFunc destroy_data)
  332: {
  333: 	axl_return_if_fail (list);
  334: 	list->destroy_data = destroy_data;
  335: 	return;
  336: }
  337: 
  338: /** 
  339:  * @brief Allows to copy the provided list, returning a newly
  340:  * allocated structure. 
  341:  *
  342:  * The copy process can also perform a deep copy for all data stored
  343:  * inside the \ref axlList. However, for this purpose it is required
  344:  * to provide a duplication function that is able to implement the
  345:  * duplication operation over the data received. 
  346:  * 
  347:  * This handler is optional, and in the case it is not provided, the
  348:  * list returned will be a copy having reference to the content
  349:  * stored.
  350:  *
  351:  * NOTE: the function also copy the destroy and equal function
  352:  * configured at \ref axl_list_new. If you want to disable destroy
  353:  * function on the copy returned you must use \ref
  354:  * axl_list_set_destroy_func, passing NULL as destroy handler.
  355:  * 
  356:  * @param list The list to copy.
  357:  * @param func The duplication function used to perform a deep copy (optional handler).
  358:  * 
  359:  * @return A newly allocated \ref axlList with the same configuration
  360:  * as the one provided.
  361:  */
  362: axlList  * axl_list_copy   (axlList * list, axlDuplicateFunc func)
  363: {
  364: 	axlList   * result;
  365: 	int         iterator;
  366: 	axlPointer  data;
  367: 
  368: 	axl_return_val_if_fail (list, NULL);
  369: 
  370: 	/* create a new axl list */
  371: 	result = axl_list_new (list->are_equal, list->destroy_data);
  372: 
  373: 	/* if the duplicate function is NULL, remove the destroy
  374: 	 * function */
  375: 	if (func == NULL)
  376: 		result->destroy_data = NULL;
  377: 
  378: 	/* add all elements */
  379: 	iterator = 0;
  380: 	while (iterator < axl_list_length (list)) {
  381: 		/* get data pointer from the list */
  382: 		data = axl_list_get_nth (list, iterator);
  383: 
  384: 		/* try to make a copy */
  385: 		if (func != NULL)
  386: 			data = func (data);
  387: 		
  388: 		/* add the data to the new list */
  389: 		axl_list_add (result, data);
  390: 
  391: 		/* update index */
  392: 		iterator++;
  393: 	}
  394: 
  395: 	return result;
  396: }
  397: 
  398: /** 
  399:  * @brief Equal function that is prepared to receive two strings a
  400:  * return if they are equal.
  401:  *
  402:  * This function is provided as a convenience implementation for the
  403:  * \ref axl_list_new function, allowing to store strings inside the
  404:  * given list.
  405:  * 
  406:  * The function will return 0 if the string are equal and 1 if
  407:  * not. This will cause strings to be append at the end of the list.
  408:  * 
  409:  * @param a The first string to compare.
  410:  * @param b The second string to compare.
  411:  */
  412: int      axl_list_equal_string (axlPointer a, axlPointer b)
  413: {
  414: 	int length;
  415: 
  416: 	axl_return_val_if_fail (a, 1);
  417: 	axl_return_val_if_fail (b, 1);
  418: 
  419: 	/* get length */
  420: 	length = strlen (a);
  421: 
  422: 	/* check first that both strings have the same length */
  423: 	if (length != strlen (b))
  424: 		return 1;
  425: 
  426: 	if (axl_stream_cmp (a, b, length))
  427: 		return 0;
  428: 	/* differs */
  429: 	return 1;
  430: }
  431: 
  432: /** 
  433:  * @brief Works like \ref axl_list_equal_string but ordering strings
  434:  * stored.
  435:  *
  436:  * @param a The first string to compare.
  437:  * @param b The second string to compare.
  438:  *
  439:  * @return 0 if both are equal, -1 if a shold go before b and 1 if a
  440:  * should go after b.
  441:  */
  442: int axl_list_order_string (axlPointer a, axlPointer b)
  443: {
  444: 	int value;
  445: 
  446: 	value = strcmp (a, b);
  447: 	if (value == 0)
  448: 		return value;
  449: 	if (value > 0)
  450: 		return -1;
  451: 	return 1;
  452: }
  453: 
  454: /** 
  455:  * @brief Equal function that is prepared to receive to integers and
  456:  * return if they are equal.
  457:  *
  458:  * It is assumed that integers are stored in the list using the
  459:  * following:
  460:  * \code
  461:  * axl_list_add (list, INT_TO_PTR (integer));
  462:  * \endcode
  463:  *
  464:  * You can use this function to create an \ref axlList that stores
  465:  * integer values as follows:
  466:  * \code
  467:  * list = axl_list_new (axl_list_equal_int, NULL);
  468:  * \endcode
  469:  *
  470:  * The list created with this function will order data from litter to
  471:  * greater values.
  472:  * 
  473:  * 
  474:  * @param a A reference to the first integer.
  475:  * @param b A reference to the second integer.
  476:  * 
  477:  * @return 0 if values received are equal, and 1 if b is greater than
  478:  * b. Otherwise -1 is returned.
  479:  */
  480: int        axl_list_equal_int    (axlPointer a, axlPointer b)
  481: {
  482: 	/* especial case where a 0 is stored */
  483: 	if (PTR_TO_INT (a) == PTR_TO_INT (b))
  484: 		return 0;
  485: 	else if (PTR_TO_INT (a) < PTR_TO_INT (b))
  486: 		return -1;
  487: 	else
  488: 		return 1;
  489: }
  490: 
  491: /** 
  492:  * @brief An equal function that could be used to make elements to be
  493:  * stored inside an \ref axlList at the end as the are added, without
  494:  * replacing any previously added item.
  495:  * 
  496:  *
  497:  * If it is needed to create a list that stores elements at the end as
  498:  * they are added, this function could be used as the \ref
  499:  * axlEqualFunc, while calling to axl_list_new.
  500:  * 
  501:  * @param a First item.
  502:  * @param b Second item.
  503:  * 
  504:  * @return The function always return 1.
  505:  *
  506:  * NOTE: If you use this function and your intention is to remove
  507:  * items (without calling to axl_list_free) you must use \ref
  508:  * axl_list_remove_ptr or \ref axl_list_unlink_ptr since \ref
  509:  * axl_list_remove and \ref axl_list_unlink relays on the equal
  510:  * function to find and remove the item. Because this function never
  511:  * return 0, the item is never removed.
  512:  */
  513: int        axl_list_always_return_1 (axlPointer a, axlPointer b)
  514: {
  515: 	return 1;
  516: }
  517: 
  518: /** 
  519:  * @brief Allows to store a new element inside the list, using the
  520:  * provided data.
  521:  *
  522:  * The function will fail to perform any action if a null reference is
  523:  * provided to the function.
  524:  * 
  525:  * @param list The list where the element will be added.
  526:  *
  527:  * @param pointer The pointer to store.
  528:  *
  529:  * NOTE: The function uses the equal function defined at \ref
  530:  * axl_list_new. If the function shows that the item to be added is
  531:  * already added (because the equal function returns 0, then the item
  532:  * won't be added.
  533:  *
  534:  */
  535: void      axl_list_add    (axlList * list, axlPointer pointer)
  536: {
  537: 	axlListNode * new_node;
  538: 	axlListNode * node;
  539: 	axlListNode * node2;
  540: 
  541: 
  542: 	/* perform some environment checkings */
  543: 	axl_return_if_fail (list);
  544: 	
  545: 	new_node         = __axl_list_get_next_node_available (list); 
  546: 	/* check returned node */
  547: 	if (new_node == NULL)
  548: 		return;
  549: 	new_node->data   = pointer;
  550: 	
  551: 	/* check basic case */
  552: 	if (list->first_node == NULL) {
  553: 		list->first_node = new_node;
  554: 		list->last_node  = new_node;
  555: 		list->length     = 1;
  556: 		return;
  557: 	}
  558: 	
  559: 	/* complex case */
  560: 	node  = list->first_node;
  561: 	node2 = list->last_node;
  562: 
  563: 	/* lookup */
  564: 	while ((node != NULL) || (node2 != NULL)) {
  565: 		/* lookup the head */
  566: 		if (node != NULL) {
  567: 			switch (list->are_equal (node->data, pointer)) {
  568: 			case -1:
  569: 				/* the node should be added before node  */
  570: 				new_node->next     = node;
  571: 				new_node->previous = node->previous;
  572: 				node->previous     = new_node;
  573: 
  574: 				/* if new previous is null do not update it */
  575: 				if (new_node->previous != NULL)
  576: 					new_node->previous->next = new_node;
  577: 				else
  578: 					list->first_node         = new_node;
  579: 
  580: 				/* update list length */
  581: 				list->length ++;
  582: 				return;
  583: 			case 0:
  584: 				/* the node found is equal, do not perform any operation */
  585: 				return;
  586: 			case 1:
  587: 			default:
  588: 				/* the node should be added after */
  589: 				node = node->next;
  590: 				break;
  591: 			}
  592: 		} /* end if */
  593: 
  594: 		/* lookup from the tail */
  595: 		if (node2 != NULL) {
  596: 			switch (list->are_equal (node2->data, pointer)) {
  597: 			case -1:
  598: 			default:
  599: 				/* the node should be added before node  */
  600: 				node2 = node2->previous;
  601: 				break;
  602: 			case 0:
  603: 
  604: 				/* the node found is equal, do not perform any operation */
  605: 				return;
  606: 			case 1:
  607: 				/* the node should be added after */
  608: 				new_node->previous = node2;
  609: 				new_node->next     = node2->next;
  610: 				node2->next        = new_node;
  611: 				
  612: 				/* do not update if next is NULL */
  613: 				if (new_node->next != NULL)
  614: 					new_node->next->previous  = new_node;
  615: 				else
  616: 					list->last_node           = new_node;
  617: 
  618: 				/* update length size */
  619: 				list->length ++;
  620: 				return;
  621: 			}
  622: 		} /* end if */
  623: 	} /* end while */
  624: 
  625: 	/* nothing more to do */
  626: 	return;
  627: }
  628: 
  629: /** 
  630:  * @brief Allows to adds the provided item to the given list at the
  631:  * selected position.
  632:  *
  633:  * The function will perform an indexed addition, using the value
  634:  * <b>position</b>, by-passing current list configuration (\ref
  635:  * axl_list_new).
  636:  *
  637:  * If the position is greater than the length of the list, the item is
  638:  * added at the end of the list. If the position is 0, the item is
  639:  * added at the begin (equivalent to call \ref axl_list_prepend). 
  640:  *
  641:  * If an item is found at the provided position, the element is added
  642:  * before the already found.
  643:  * 
  644:  * @param list The list where the addition operation will be performed.
  645:  * 
  646:  * @param pointer The item to add to the list.
  647:  *
  648:  * @param position Position where the addition operation will be
  649:  * performed. Values allowed ranges from 0 up to list length - 1.
  650:  */
  651: void       axl_list_add_at (axlList * list, axlPointer pointer, int position)
  652: {
  653: 	int           iterator;
  654: 	axlListNode * node;
  655: 	axlListNode * new_node;
  656: 
  657: 	/* check incoming values */
  658: 	axl_return_if_fail (list);
  659: 
  660: 	/* check if we have a prepend operation */
  661: 	if (position <= 0) {
  662: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "adding item using prepend");
  663: 		/* prepend */
  664: 		axl_list_prepend (list, pointer);
  665: 
  666: 		return;
  667: 	}
  668: 	/* check if we have an append operation */
  669: 	if (position >= list->length) {
  670: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "adding item using append (position=%d >= length=%d)",
  671: 			   position, list->length);
  672: 		/* append */
  673: 		axl_list_append (list, pointer);
  674: 		
  675: 		return;
  676: 	}
  677: 	
  678: 	/* allocate a new node */
  679: 	new_node         = __axl_list_get_next_node_available (list); 
  680: 	/* check returned node */
  681: 	if (new_node == NULL)
  682: 		return;
  683: 	new_node->data   = pointer;
  684: 	
  685: 
  686: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "looking node position: %d", position);
  687: 
  688: 	/* basic case isn't reached here (remove first and last
  689: 	 * cases) */
  690: 	iterator = 1;
  691: 	node     = list->first_node->next;
  692: 	while (iterator < position) {
  693: 
  694: 		/* get the next element */
  695: 		node = node->next;
  696: 		
  697: 		/* update the iterator */
  698: 		iterator++;
  699: 	}
  700: 
  701: 	__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "adding item at: %d", iterator);
  702: 
  703: 	/* add the element */
  704: 	new_node->previous = node->previous;
  705: 	if (node->previous != NULL)
  706: 		node->previous->next = new_node;
  707: 	
  708: 	new_node->next     = node;
  709: 	node->previous     = new_node;
  710: 
  711: 	/* update number of items inside */
  712: 	list->length++;
  713: 	return;
  714: }
  715: 
  716: /** 
  717:  * @brief Allows to add a node to the provided list, at the first
  718:  * position, without taking into consideration current \ref axlList
  719:  * configuration (\ref axlEqualFunc at \ref axl_list_new). 
  720:  * 
  721:  * @param list The list where the data will be added at the first
  722:  * position.
  723:  *
  724:  * @param pointer The pointer to add.
  725:  */
  726: void       axl_list_prepend (axlList * list, axlPointer pointer)
  727: {
  728: 	axlListNode * new_node;
  729: 
  730: 	axl_return_if_fail (list);
  731: 	
  732: 	/* simulate adding the node at the first position */
  733: 	new_node         = __axl_list_get_next_node_available (list); 
  734: 	/* check returned node */
  735: 	if (new_node == NULL)
  736: 		return;
  737: 	new_node->data   = pointer;
  738: 
  739: 	/* make the new node the be the first one */
  740: 	if (list->first_node == NULL) {
  741: 		list->first_node = new_node;
  742: 		list->last_node  = new_node;
  743: 	}else {
  744: 		list->first_node->previous = new_node;
  745: 		new_node->next             = list->first_node;
  746: 		list->first_node           = new_node;
  747: 	}
  748: 
  749: 	/* update number of items inside */
  750: 	list->length++;
  751: 	
  752: 	return;
  753: }
  754: 
  755: 
  756: /** 
  757:  * @brief Allows to add a node to the provided list, at the last
  758:  * position, without taking into consideration current \ref axlList
  759:  * configuration (\ref axlEqualFunc at \ref axl_list_new). 
  760:  * 
  761:  * @param list The list where the data will be added at the last
  762:  * position.
  763:  *
  764:  * @param pointer The pointer to add.
  765:  */
  766: void       axl_list_append  (axlList * list, axlPointer pointer)
  767: {
  768: 	axlListNode * new_node;
  769: 
  770: 	axl_return_if_fail (list);
  771: 	
  772: 	/* simulate adding the node at the first position */
  773: 	new_node         = __axl_list_get_next_node_available (list); 
  774: 	/* check allocated node */
  775: 	if (new_node == NULL)
  776: 		return;
  777: 	new_node->data   = pointer;
  778: 
  779: 	/* make the new node the be the first one */
  780: 	if (list->last_node == NULL) {
  781: 		list->first_node  = new_node;
  782: 		list->last_node   = new_node;
  783: 	}else {
  784: 		list->last_node->next  = new_node;
  785: 		new_node->previous     = list->last_node;
  786: 		list->last_node        = new_node;
  787: 	}
  788: 
  789: 	/* update number of items inside */
  790: 	list->length++;
  791: 	
  792: 	return;
  793: }
  794: 
  795: /** 
  796:  * @internal Internal list lookup using a linear search, checking all
  797:  * items inside the list taking into considerations hints provided by
  798:  * equal function.
  799:  * 
  800:  * @param list The list where the linear search will be performed.
  801:  * @param pointer The pointer that is being looked up.
  802:  * 
  803:  * @return A reference to the internal axl list node containing the
  804:  * pointer.
  805:  */
  806: axlListNode * axl_list_internal_linear_lookup (axlList    * list, 
  807: 					       axlPointer    pointer)
  808: {
  809: 	axlListNode * node;
  810: 
  811: 	axl_return_val_if_fail (list, NULL);
  812: 
  813: 	/* complex case */
  814: 	node  = list->first_node;
  815: 
  816: 	/* lookup */
  817: 	while (node != NULL) {
  818: 		if (list->are_equal (node->data, pointer) == 0)
  819: 			return node;
  820: 
  821: 		/* the node should be after this one */
  822: 		node = node->next;
  823: 		
  824: 	} /* end while */
  825: 
  826: 	return NULL;
  827: }
  828: 
  829: /** 
  830:  * @internal Internal list lookup using a linear search, checking all
  831:  * items inside the list withtout taking into considerations hints
  832:  * provided by equal function (search by pointer).
  833:  * 
  834:  * @param list The list where the linear search will be performed.
  835:  * @param pointer The pointer that is being looked up.
  836:  * 
  837:  * @return A reference to the internal axl list node containing the
  838:  * pointer.
  839:  */
  840: axlListNode * axl_list_internal_linear_lookup_ptr (axlList    * list, 
  841: 						   axlPointer    pointer)
  842: {
  843: 	axlListNode * node;
  844: 
  845: 	axl_return_val_if_fail (list, NULL);
  846: 
  847: 	/* complex case */
  848: 	node  = list->first_node;
  849: 
  850: 	/* lookup */
  851: 	while (node && node->data != pointer) {
  852: 		/* the node should be after this one */
  853: 		node = node->next;
  854: 	} /* end while */
  855: 
  856: 	/* return current result */
  857: 	return node;
  858: }
  859: 
  860: /** 
  861:  * @internal
  862:  * @brief Internal lookup function to locate the axlListNode that contains the pointer.
  863:  *
  864:  * 
  865:  * @param list The list where the lookup will be performed.
  866:  * @param pointer The pointer data to lookup.
  867:  * 
  868:  * @return A reference to the \ref axlListNode or NULL if no pointer
  869:  * is found.
  870:  */
  871: axlListNode * axl_list_internal_lookup (axlList * list, axlPointer pointer)
  872: {
  873: 	axlListNode * node;
  874: 	axlListNode * node2;
  875: 
  876: 	axl_return_val_if_fail (list, NULL);
  877: 	axl_return_val_if_fail (pointer, NULL);
  878: 
  879: 	/* complex case */
  880: 	node  = list->first_node;
  881: 	node2 = list->last_node;
  882: 
  883: 	/* lookup */
  884: 	while ((node != NULL) || (node2 != NULL)) {
  885: 		/* lookup the head */
  886: 		if (node != NULL) {
  887: 			switch (list->are_equal (node->data, pointer)) {
  888: 			case -1:
  889: 			default:
  890: 				/* node should be before the node
  891: 				 * found. So we are not going to find
  892: 				 * a node that is lower, the element
  893: 				 * is not in the list.
  894: 				 */
  895: 				return NULL;
  896: 			case 0:
  897: 				return node;
  898: 			case 1:
  899: 				/* the node should be after this one */
  900: 				node = node->next;
  901: 				break;
  902: 			}
  903: 		} /* end if */
  904: 
  905: 		/* lookup from the tail */
  906: 		if (node2 != NULL) {
  907: 			switch (list->are_equal (node2->data, pointer)) {
  908: 			case -1:
  909: 				/* the node should be added before node  */
  910: 				node2 = node2->next;
  911: 				break;
  912: 			case 0:
  913: 				return node2;
  914: 			case 1:
  915: 			default:
  916: 				/* it seems that the node should be
  917: 				 * found after this node but this is
  918: 				 * not going to be possible. The node is not in the list.
  919: 				 */
  920: 				return NULL;
  921: 			}
  922: 		} /* end if */
  923: 	} /* end while */
  924: 
  925: 	return NULL;
  926: }
  927: 
  928: 
  929: /** 
  930:  * @internal
  931:  *
  932:  * @brief Allows to lookup the pointer stored, inside the provided
  933:  * list, on the given position.
  934:  * 
  935:  * @param list The list where the operation will be performed.
  936:  * @param position The position to lookup for stored data.
  937:  * 
  938:  * @return A reference or NULL if fails.
  939:  */
  940: axlListNode * axl_list_internal_get_nth (axlList * list, int position)
  941: {
  942: 	axlListNode * node;
  943: 	int           iterator = 0;
  944: 
  945: 	axl_return_val_if_fail (list, NULL);
  946: 	axl_return_val_if_fail (position >= 0 && position < list->length, NULL);
  947: 	
  948: 	/* iterate until the node is found */
  949: 	node = list->first_node;
  950: 	while (node != NULL && (iterator != position)) {
  951: 		iterator ++;
  952: 		node = node->next;
  953: 	}
  954: 
  955: 	/* return data found */
  956: 	if (iterator == position)
  957: 		return node;
  958: 	return NULL;
  959: }
  960: 
  961: /* remove the selected node */
  962: void __axl_list_common_remove_selected_node (axlList * list, axlListNode * node, 
  963: 					     axl_bool alsoRemove)
  964: {
  965: 	axlPointer pointer;
  966: 
  967: 	/* do not remove anything if a null reference is received */
  968: 	if (node == NULL)
  969: 		return;
  970: 	
  971: 	/* get a reference to the pointer */
  972: 	pointer = node->data;
  973: 	
  974: 	if (node->previous == NULL)
  975: 		list->first_node = node->next;
  976: 	else
  977: 		node->previous->next = node->next;
  978: 	
  979: 	if (node->next == NULL)
  980: 		list->last_node      = node->previous;
  981: 	else
  982: 		node->next->previous = node->previous;
  983: 	
  984: 	/* release user space allocated memory
  985: 	 * if defined destroy function */
  986: 	if (alsoRemove && (list->destroy_data != NULL))
  987: 		list->destroy_data (pointer);
  988: 	
  989: 	/* release memory allocated by the node */
  990: 	__axl_list_dispose_node (list, node); 
  991: 
  992: 	/* decrease list length */
  993: 	list->length--;
  994: 
  995: 	/* nothing more to do */
  996: 	return;
  997: }
  998: 
  999: /** 
 1000:  * @internal
 1001:  *
 1002:  * Internal support for axl_list_remove and axl_list_unlink
 1003:  * function. The function perform a node removing, the one that
 1004:  * contains the node pointed by the provided pointer, and making a
 1005:  * node deallocation according to the configuration of the
 1006:  * <b>alsoRemove</b>.
 1007:  * 
 1008:  * @param list The list where the operation will be performed.
 1009:  *
 1010:  * @param pointer The pointer to remove
 1011:  *
 1012:  * @param alsoRemove Also call to destroy function.
 1013:  *
 1014:  * @param byPtr Makes the linear search to be done by pointer.
 1015:  */
 1016: void     axl_list_common_remove (axlList * list, axlPointer pointer, axl_bool alsoRemove, axl_bool byPtr)
 1017: {
 1018: 	axlListNode * node;
 1019: 
 1020: 	axl_return_if_fail (list);
 1021: 
 1022: 	/* complex case */
 1023: 	if (byPtr)
 1024: 		node = axl_list_internal_linear_lookup_ptr (list, pointer);
 1025: 	else
 1026: 		node  = axl_list_internal_linear_lookup (list, pointer);
 1027: 	if (node == NULL) {
 1028: 		__axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "unable to find item by pointer (0x%x)",
 1029: 			   pointer);
 1030: 		return;
 1031: 	}
 1032: 
 1033: 	/* remove the selected node */
 1034: 	__axl_list_common_remove_selected_node (list, node, alsoRemove);
 1035: 	
 1036: 	return;	
 1037: }
 1038: 
 1039: 
 1040: /** 
 1041:  * @brief Allows to remove the given pointer from the list.
 1042:  *
 1043:  * The element referenced by <b>pointer</b> will be removed from the
 1044:  * list, include the memory allocated if a destroy function were
 1045:  * provided.
 1046:  *
 1047:  * If it is required to remove a pointer from the list, without
 1048:  * calling to the destroy function, you can use \ref axl_list_unlink.
 1049:  *
 1050:  * The function will fail to work if references provided are NULL.
 1051:  *
 1052:  * @param list The list where the removal operation will be performed.
 1053:  * @param pointer The pointer where the 
 1054:  *
 1055:  * NOTE: The function uses the current equal function configured. A
 1056:  * not properly configured equal function will make this function to
 1057:  * not remove the item selected. If you are trying to remove by
 1058:  * pointer, you can use \ref axl_list_remove_ptr.
 1059:  */
 1060: void      axl_list_remove (axlList * list, axlPointer pointer)
 1061: {
 1062: 
 1063: 	/* perform a complete removing */
 1064: 	axl_list_common_remove (list, pointer, 
 1065: 				/* alsoRemove */
 1066: 				axl_true, 
 1067: 				/* byPtr */ 
 1068: 				axl_false);
 1069: 
 1070: 	return;
 1071: }
 1072: 
 1073: /** 
 1074:  * @internal Implementation that removes or unlinks a selected node at
 1075:  * a particular position.
 1076:  */
 1077: void       __axl_list_remove_at_common  (axlList * list, int position, axl_bool remove_node)
 1078: {
 1079: 	axlListNode * node;
 1080: 	int           iterator = 0;
 1081: 
 1082: 	axl_return_if_fail (list);
 1083: 	
 1084: 	/* find the item by position */
 1085: 	node  = list->first_node;
 1086: 
 1087: 	/* lookup */
 1088: 	while (node) {
 1089: 		/* return selected node */
 1090: 		if (iterator == position)
 1091: 			break;
 1092: 		
 1093: 		/* the node should be after this one */
 1094: 		node = node->next;
 1095: 
 1096: 		/* next iterator */
 1097: 		iterator++;
 1098: 	} /* end while */
 1099: 
 1100: 	if (node) {
 1101: 		/* remove selected node */
 1102: 		__axl_list_common_remove_selected_node (list, node, remove_node);
 1103: 	} /* end if */
 1104: 	return;
 1105: }
 1106: 
 1107: /** 
 1108:  * @brief Allows to remove a particular item inside the list at a
 1109:  * selected position.
 1110:  *
 1111:  * This function also deallocates the memory used by the node located
 1112:  * at the particular position. In the case only a removal operation is
 1113:  * required use \ref axl_list_unlink_at.
 1114:  * 
 1115:  * @param list The list where the remove operation will take place.
 1116:  *
 1117:  * @param position The position where the removal operation will take
 1118:  * place. Position values ranges from 0 up to (N - 1).
 1119:  */
 1120: void       axl_list_remove_at  (axlList * list, int position)
 1121: {
 1122: 	/* call to common implementation */
 1123: 	__axl_list_remove_at_common (list, position, axl_true);
 1124: 	return;
 1125: }
 1126: 
 1127: /** 
 1128:  * @brief Allows to remove the provided pointer from the list (calling
 1129:  * to the destroy function defined).
 1130:  *
 1131:  * Unlike \ref axl_list_remove, which removes the element selected by
 1132:  * using the equal function configured at \ref axl_list_new, this
 1133:  * function allows to perform a remove operation by pointer.
 1134:  * 
 1135:  * @param list The list on which the operation is performed.
 1136:  *
 1137:  * @param pointer The pointer to remove from the list.
 1138:  */
 1139: void axl_list_remove_ptr (axlList * list, axlPointer pointer)
 1140: {
 1141: 	/* perform a complete removing */
 1142: 	axl_list_common_remove (list, pointer, 
 1143: 				/* alsoRemove */
 1144: 				axl_true, 
 1145: 				/* byPtr */ 
 1146: 				axl_true);
 1147: }
 1148: 
 1149: /** 
 1150:  * @brief Removes the given pointer from the list, without calling the
 1151:  * destroy function, even when it is configured.
 1152:  * 
 1153:  * @param list The list where the operation will be performed.
 1154:  *
 1155:  * @param pointer The pointer to remove.
 1156:  */
 1157: void       axl_list_unlink (axlList * list, axlPointer pointer)
 1158: {
 1159: 	/* perform a complete removing */
 1160: 	axl_list_common_remove (list, pointer, 
 1161: 				/* alsoRemove */
 1162: 				axl_false, 
 1163: 				/* byPtr */ 
 1164: 				axl_false);
 1165: 
 1166: 	return;
 1167: }
 1168: 
 1169: /** 
 1170:  * @brief Allows to remove the provided item from the axl list
 1171:  * withtout using the equal function provided (remove by pointer) and
 1172:  * without calling to the associated destroy function.
 1173:  * 
 1174:  * @param list The list where the operation will be implemented.
 1175:  *
 1176:  * @param pointer the pointer to remove from the list without calling
 1177:  * to the destroy function.
 1178:  */
 1179: void axl_list_unlink_ptr (axlList * list, axlPointer pointer)
 1180: {
 1181: 
 1182: 	/* perform an unlink operation, without using equal
 1183: 	 * function */
 1184: 	/* perform a complete removing */
 1185: 	axl_list_common_remove (list, pointer, 
 1186: 				/* alsoRemove */
 1187: 				axl_false, 
 1188: 				/* byPtr */ 
 1189: 				axl_true);
 1190: 	
 1191: 	return;
 1192: }
 1193: 
 1194: /** 
 1195:  * @brief Allows to unlink a particular item inside the list at a
 1196:  * selected position.
 1197:  *
 1198:  * This function DO NOT deallocates the memory used by the node located
 1199:  * at the particular position. In the case a complete removal operation is
 1200:  * required use \ref axl_list_remove_at.
 1201:  * 
 1202:  * @param list The list where the unlink operation will take place.
 1203:  *
 1204:  * @param position The position where the unlink operation will take
 1205:  * place. Position values ranges from 0 up to (N - 1).
 1206:  */
 1207: void       axl_list_unlink_at  (axlList * list, int position)
 1208: {
 1209: 	/* call to common implementation */
 1210: 	__axl_list_remove_at_common (list, position, axl_false);
 1211: 	return;
 1212: }
 1213: 
 1214: 
 1215: /** 
 1216:  * @brief Allows to remove the first element, calling to the destroy
 1217:  * function if defined.
 1218:  * 
 1219:  * @param list The list where the first element will be removed.
 1220:  */
 1221: void       axl_list_remove_first (axlList * list)
 1222: {
 1223: 
 1224: 	axl_return_if_fail (list);
 1225: 
 1226: 	/* do not perform any operation if no node is stored */
 1227: 	if (list->first_node == NULL)
 1228: 		return;
 1229: 
 1230: 	/* remove the selected node */
 1231: 	__axl_list_common_remove_selected_node (list, list->first_node, axl_true);
 1232: 
 1233: 	return;
 1234: }
 1235: 
 1236: /** 
 1237:  * @brief Allows to remove the first element from the list without
 1238:  * calling to the destroy function, even with it is defined.
 1239:  * 
 1240:  * @param list The list where the first element will be removed.
 1241:  */
 1242: void       axl_list_unlink_first (axlList * list)
 1243: {
 1244: 
 1245: 	axl_return_if_fail (list);
 1246: 
 1247: 	/* do not perform any operation if no node is stored */
 1248: 	if (list->first_node == NULL)
 1249: 		return;
 1250: 
 1251: 	/* remove the selected node */
 1252: 	__axl_list_common_remove_selected_node (list, list->first_node, axl_false);
 1253: 
 1254: 	return;
 1255: }
 1256: 
 1257: /** 
 1258:  * @brief Allows to remove the last element, calling to the destroy
 1259:  * function if defined.
 1260:  * 
 1261:  * @param list The list where the last element will be removed.
 1262:  */
 1263: void       axl_list_remove_last (axlList * list)
 1264: {
 1265: 	axl_return_if_fail (list);
 1266: 
 1267: 	/* do not perform any operation if no node is stored */
 1268: 	if (list->last_node == NULL)
 1269: 		return;
 1270: 
 1271: 	/* remove the selected node */
 1272: 	__axl_list_common_remove_selected_node (list, list->last_node, axl_true);
 1273: 
 1274: 	return;
 1275: }
 1276: 
 1277: /** 
 1278:  * @brief Allows to remove the last element from the list without
 1279:  * calling to the destroy function, even with it is defined.
 1280:  * 
 1281:  * @param list The list where the last element will be removed.
 1282:  */
 1283: void       axl_list_unlink_last (axlList * list)
 1284: {
 1285: 	axl_return_if_fail (list);
 1286: 
 1287: 	/* do not perform any operation if no node is stored */
 1288: 	if (list->last_node == NULL)
 1289: 		return;
 1290: 
 1291: 	/* remove the selected node */
 1292: 	__axl_list_common_remove_selected_node (list, list->last_node, axl_false);
 1293: 
 1294: 	return;
 1295: }
 1296: 
 1297: /** 
 1298:  * @brief Allows to check if the given pointer is stored on the given
 1299:  * list.
 1300:  * 
 1301:  * @param list The list where the lookup will be performed.
 1302:  *
 1303:  * @param pointer The pointer to lookup.
 1304:  * 
 1305:  * @return \ref axl_true if the element is stored on the list,
 1306:  * otherwise axl_false is returned. The function will fail to lookup
 1307:  * if a NULL reference is received, either the list or the pointer.
 1308:  */
 1309: axl_bool          axl_list_exists (axlList * list, axlPointer pointer)
 1310: {
 1311: 	axl_return_val_if_fail (list, axl_false);
 1312: 	axl_return_val_if_fail (pointer, axl_false);
 1313: 
 1314: 	if (axl_list_internal_lookup (list, pointer) != NULL)
 1315: 		return axl_true;
 1316: 	return axl_false;
 1317: }
 1318: 
 1319: /** 
 1320:  * @brief Allows to check if the provided list is empty (no element
 1321:  * stored).
 1322:  * 
 1323:  * @param list The list to check for emptyness.
 1324:  * 
 1325:  * @return axl_true if the list is empty, axl_false if not. The function
 1326:  * return axl_false in the case a null reference is provided.
 1327:  */
 1328: axl_bool       axl_list_is_empty  (axlList * list)
 1329: {
 1330: 	axl_return_val_if_fail (list, axl_false);
 1331: 
 1332: 	/* check if the first node is defined */
 1333: 	return (list->first_node == NULL);
 1334: }
 1335: 
 1336: /** 
 1337:  * @brief Allows to check if the given pointer is stored on the given position.
 1338:  *
 1339:  * @param list The list where the operation will be run.
 1340:  * @param pointer The pointer to check.
 1341:  * @param position The position where is expected to find the pointer.
 1342:  * 
 1343:  * @return axl_true if the given data, referenced by the pointer, is
 1344:  * stored on the given position.
 1345:  */
 1346: axl_bool           axl_list_exists_at (axlList * list, axlPointer pointer, int position)
 1347: {
 1348: 	axlListNode * node;
 1349: 
 1350: 	node = axl_list_internal_get_nth (list, position);
 1351: 	if (node != NULL) {
 1352: 		if (! list->are_equal (node->data, pointer))
 1353: 			return axl_true;
 1354: 	}
 1355: 	return axl_false;
 1356: }
 1357: 
 1358: /** 
 1359:  * @brief Returns the first element stored on the list.
 1360:  *
 1361:  *
 1362:  * @param list The list where the first element stored will be
 1363:  * returned.
 1364:  * 
 1365:  * @return An \ref axlPointer containing the data stored on the list.
 1366:  */
 1367: axlPointer axl_list_get_first (axlList * list)
 1368: {
 1369: 	axl_return_val_if_fail (list, NULL);
 1370: 
 1371: 	if (list->first_node == NULL)
 1372: 		return NULL;
 1373: 	return list->first_node->data;
 1374: }
 1375: 
 1376: /** 
 1377:  * @brief Returns the last element stored on the list.
 1378:  * 
 1379:  * @param list The list where the last element will be returned.
 1380:  * 
 1381:  * @return An \ref axlPointer reference containing the last stored
 1382:  * value.
 1383:  */
 1384: axlPointer axl_list_get_last  (axlList * list)
 1385: {
 1386: 	axl_return_val_if_fail (list, NULL);
 1387: 
 1388: 	if (list->last_node == NULL)
 1389: 		return NULL;
 1390: 	return list->last_node->data;
 1391: }
 1392: 
 1393: /** 
 1394:  * @brief Allows to get current pointer stored at the given position.
 1395:  * 
 1396:  * @param list The list where the data will be retrieved.
 1397:  *
 1398:  * @param position A value ranging from 0 up to the the list lenght -
 1399:  * 1.
 1400:  * 
 1401:  * @return The \ref axlPointer stored on the given position or NULL if
 1402:  * fail.
 1403:  */
 1404: axlPointer axl_list_get_nth   (axlList * list, int position)
 1405: {
 1406: 	axlListNode * node;
 1407: 
 1408: 	node = axl_list_internal_get_nth (list, position);
 1409: 	if (node != NULL)
 1410: 		return node->data;
 1411: 	return NULL;
 1412: }
 1413: 
 1414: /** 
 1415:  * @brief Allows to perform a linear lookup on the list provided,
 1416:  * givin a function that is used to now the object to return due to
 1417:  * the lookup.
 1418:  *
 1419:  * The function can also be used as a foreach function. The following
 1420:  * example shows how to launch the function and perform a tasks on the
 1421:  * lookup function:
 1422:  * \code
 1423:  * // perform the lookup 
 1424:  * return axl_list_lookup (list, __find_item, name);
 1425:  *
 1426:  * // the lookup function 
 1427:  * axl_bool __find_item (axlPointer _element, axlPointer data)
 1428:  * {
 1429:  *	SomeItem * element = _element;
 1430:  *	char     * name    = data;
 1431:  *
 1432:  *	// check the name 
 1433:  *	if (axl_cmp (element->name, name))
 1434:  *		return axl_true;
 1435:  *
 1436:  *	// it is not the element 
 1437:  *	return axl_false;
 1438:  * }
 1439:  * \endcode
 1440:  *
 1441:  * In the case you create a list to hold string values, you can use
 1442:  * \ref axl_list_find_string as lookup function predefined to perform
 1443:  * the search.
 1444:  * 
 1445:  * @param list The list where the lookup will be performed.
 1446:  *
 1447:  * @param func The function to use to perform the lookup.
 1448:  * 
 1449:  * @param data User defined data that will be passed to the func provided.
 1450:  * 
 1451:  * @return A pointer to the object found or NULL if no item was found.
 1452:  */
 1453: axlPointer axl_list_lookup    (axlList * list, axlLookupFunc func, axlPointer data)
 1454: {
 1455: 	axlListNode * node;
 1456: 	axl_return_val_if_fail (list, NULL);
 1457: 	axl_return_val_if_fail (func, NULL);
 1458: 
 1459: 	/* get the first pointer */
 1460: 	node = list->first_node;
 1461: 	do {
 1462: 		/* if the next node to check is NULL, terminate the
 1463: 		 * lookup. */
 1464: 		if (node == NULL)
 1465: 			return NULL;
 1466: 
 1467: 		/* check if the node found is the one looked up */
 1468: 		if (func (node->data, data))
 1469: 			return node->data;
 1470: 
 1471: 		/* seems not, update to the next reference */
 1472: 		node = node->next;
 1473: 		
 1474: 	}while (1);
 1475: 
 1476: 	/* return no node found */
 1477: 	return NULL;
 1478: }
 1479: 
 1480: /** 
 1481:  * @brief Helper function that could be used at \ref axl_list_lookup if
 1482:  * the list created only contains strings.
 1483:  *
 1484:  * Use this function as a parameter for the lookup function at \ref
 1485:  * axl_list_lookup.
 1486:  *
 1487:  * @param element The element at the list, in this case, an string value.
 1488:  *
 1489:  * @param data The data provided at \ref axl_list_lookup, in this
 1490:  * case, the value we are looking.
 1491:  * 
 1492:  * @return \ref axl_true if the string was found, \ref axl_false if not.
 1493:  */
 1494: axl_bool       axl_list_find_string (axlPointer element, axlPointer data)
 1495: {
 1496: 	/* if the string received is null, just return axl_false */
 1497: 	if (data == NULL)
 1498: 		return axl_false;
 1499: 
 1500: 	/* return the comparison status */
 1501: 	return axl_cmp ((char *) element, (char *) data);
 1502: }
 1503: 
 1504: /** 
 1505:  * @brief Allows to get current list length.
 1506:  * 
 1507:  * @param list The list to operate.
 1508:  * 
 1509:  * @return The list length or -1 if fail (the list reference received
 1510:  * is null).
 1511:  */
 1512: int       axl_list_length (axlList * list)
 1513: {
 1514: 	axl_return_val_if_fail (list, -1);
 1515: 	return list->length;
 1516: }
 1517: 
 1518: /** 
 1519:  * @brief Allows to destroy the given list, and all user space
 1520:  * associated memory if a destroy handler was provided.
 1521:  * 
 1522:  * @param list The list to destroy
 1523:  */
 1524: void      axl_list_free (axlList * list)
 1525: {
 1526: 	axlListNode * node;
 1527: 	axlListNode * node2;
 1528: 	int           iterator;
 1529: 
 1530: 	/* if a null reference is received do not oper */
 1531: 	if (list == NULL)
 1532: 		return;
 1533: 
 1534: 	node     = list->first_node;
 1535: 	while (node != NULL) {
 1536: 		if (list->destroy_data != NULL) {
 1537: 			list->destroy_data (node->data);
 1538: 		}
 1539: 		node2 = node;
 1540: 		node  = node->next;
 1541: 
 1542: 		axl_free (node2);
 1543: 	}
 1544: 
 1545: 	/* allocate a node for each available position */
 1546: 	for (iterator = 0; iterator < list->available; iterator++) {
 1547: 		axl_free (list->preallocated[iterator]);
 1548: 	}
 1549: 
 1550: 	/* free the array */
 1551: 	axl_free (list->preallocated);
 1552: 	
 1553: 	/* free the list itself */
 1554: 	axl_free (list);
 1555: 
 1556: 	return;
 1557: }
 1558: 
 1559: /* @} */
 1560: 
 1561: /**
 1562:  * \defgroup axl_list_cursor_module Axl List Cursor: Iterator support for the Axl List
 1563:  */
 1564: 
 1565: /** 
 1566:  * \addtogroup axl_list_cursor_module
 1567:  * @{
 1568:  */
 1569: 
 1570: /** 
 1571:  * @brief Allows to get a cursor to iterate the list in a linear and
 1572:  * efficient way.
 1573:  *
 1574:  * The \ref axlListCursor could be used to iterate an \ref axlList in
 1575:  * an efficient way because it stores current state (position). Then
 1576:  * using the following functions you can modify the state (current
 1577:  * position to get):
 1578:  * 
 1579:  *   - \ref axl_list_cursor_first
 1580:  *   - \ref axl_list_cursor_last
 1581:  *   - \ref axl_list_cursor_next
 1582:  *   - \ref axl_list_cursor_previous
 1583:  *
 1584:  * Finally, a function is provided to get the data stored at a
 1585:  * particular position, pointed by the current status of the cursor:
 1586:  * 
 1587:  *   - \ref axl_list_cursor_get
 1588:  *
 1589:  * You are allowed to remove elements from the list (\ref axlList)
 1590:  * having a cursor created (\ref axlListCursor), using \ref
 1591:  * axl_list_cursor_unlink. 
 1592:  *
 1593:  * Here is an example:
 1594:  * \code
 1595:  * axlPointer      value;
 1596:  * axlListCursor * cursor;
 1597:  * 
 1598:  * // create the cursor 
 1599:  * cursor   = axl_list_cursor_new (list);
 1600:  *
 1601:  * // while there are more elements 
 1602:  * while (axl_list_cursor_has_item (cursor)) {
 1603:  *
 1604:  *   // get the value 
 1605:  *   value = axl_list_cursor_get (cursor);
 1606:  *
 1607:  *
 1608:  *   // get the next 
 1609:  *   axl_list_cursor_next (cursor);
 1610:  *
 1611:  *   // update the iterator 
 1612:  *   iterator++;
 1613:  *		
 1614:  * } 
 1615:  *
 1616:  * // free the cursor 
 1617:  * axl_list_cursor_free (cursor);
 1618:  * \endcode
 1619:  * 
 1620:  * @param list The list that the new cursor (\ref axlListCursor) will
 1621:  * provide access.
 1622:  * 
 1623:  * @return A newly created \ref axlListCursor used to iterate the
 1624:  * list. Once finished you must call to \ref axl_list_cursor_free.
 1625:  */
 1626: axlListCursor * axl_list_cursor_new      (axlList * list)
 1627: {
 1628: 	axlListCursor * cursor;
 1629: 
 1630: 	axl_return_val_if_fail (list, NULL);
 1631: 
 1632: 	/* create the cursor */
 1633: 	cursor = axl_new (axlListCursor, 1);
 1634: 
 1635: 	/* initial configuration */
 1636: 	cursor->list    = list;
 1637: 	cursor->current = list->first_node;
 1638: 
 1639: 	return cursor;
 1640: }
 1641: 
 1642: /** 
 1643:  * @brief Allows to configure the cursor to point to the first item of
 1644:  * the list (if there are any).
 1645:  * 
 1646:  * @param cursor The cursor that is required to be configured to point the first item.
 1647:  */
 1648: void            axl_list_cursor_first    (axlListCursor * cursor)
 1649: {
 1650: 	axl_return_if_fail (cursor);
 1651: 
 1652: 	if (cursor->list->length == 0) {
 1653: 		cursor->current = NULL;
 1654: 		return;
 1655: 	} /* end if */
 1656: 
 1657: 	/* set the first node */
 1658: 	cursor->current = cursor->list->first_node;
 1659: 
 1660: 	return;
 1661: }
 1662: 
 1663: /** 
 1664:  * @brief Allows to configure the cursor to point to the last item of
 1665:  * the list (if there are any).
 1666:  * 
 1667:  * @param cursor The cursor that is required to be configured to point
 1668:  * to the last item.
 1669:  */
 1670: void            axl_list_cursor_last     (axlListCursor * cursor)
 1671: {
 1672: 	axl_return_if_fail (cursor);
 1673: 
 1674: 	/* set the first node */
 1675: 	cursor->current = cursor->list->last_node;
 1676: 
 1677: 	return;
 1678: }
 1679: 
 1680: /** 
 1681:  * @brief Allows to configure the cursor to point to the next item of
 1682:  * the list (if there are any).
 1683:  * 
 1684:  * @param cursor The cursor that is required to be configured to point
 1685:  * to the next item.
 1686:  */
 1687: void            axl_list_cursor_next     (axlListCursor * cursor)
 1688: {
 1689: 	axl_return_if_fail (cursor);
 1690: 
 1691: 	/* set the next node */
 1692: 	if (cursor->current != NULL)
 1693: 		cursor->current = cursor->current->next;
 1694: 
 1695: 	return;
 1696: }
 1697: 
 1698: /** 
 1699:  * @brief Allows to configure the cursor to point to the previous item
 1700:  * of the list (if there are any).
 1701:  * 
 1702:  * @param cursor The cursor that is required to be configured to point
 1703:  * to the previous item.
 1704:  */
 1705: void            axl_list_cursor_previous (axlListCursor * cursor)
 1706: {
 1707: 	axl_return_if_fail (cursor);
 1708: 
 1709: 	/* set the next node */
 1710: 	if (cursor->current != NULL)
 1711: 		cursor->current = cursor->current->previous;
 1712: 
 1713: 	return;
 1714: }
 1715: 
 1716: /** 
 1717:  * @brief Allows to check if there are more elements next to the
 1718:  * current element pointed by the cursor.
 1719:  * 
 1720:  * @param cursor The cursor that is required to return if there are
 1721:  * next items.
 1722:  * 
 1723:  * @return \ref axl_true if more items are found, otherwise \ref axl_false is
 1724:  * returned.
 1725:  */
 1726: axl_bool            axl_list_cursor_has_next (axlListCursor * cursor)
 1727: {
 1728: 	axl_return_val_if_fail (cursor, axl_false);
 1729: 
 1730: 	/* check for empty list */
 1731: 	if (cursor->current == NULL)
 1732: 		return axl_false;
 1733: 
 1734: 	/* return if the next element isn't null */
 1735: 	return (cursor->current->next != NULL);
 1736: }
 1737: 
 1738: /** 
 1739:  * @brief Allows to check if there are more elements next to the
 1740:  * current element pointed by the cursor.
 1741:  * 
 1742:  * @param cursor The cursor that is required to return if there are
 1743:  * next items.
 1744:  * 
 1745:  * @return \ref axl_true if more items are found, otherwise \ref axl_false is
 1746:  * returned.
 1747:  */
 1748: axl_bool            axl_list_cursor_has_previous (axlListCursor * cursor)
 1749: {
 1750: 	axl_return_val_if_fail (cursor, axl_false);
 1751: 
 1752: 	/* check for empty list */
 1753: 	if (cursor->current == NULL)
 1754: 		return axl_false;
 1755: 
 1756: 	/* return if the next element isn't null */
 1757: 	return (cursor->current->previous != NULL);
 1758: }
 1759: 
 1760: /** 
 1761:  * @brief Allows to know if the current position has items.
 1762:  * 
 1763:  * @param cursor The cursor that is requested to return if a call to
 1764:  * \ref axl_list_cursor_get will return data.
 1765:  * 
 1766:  * @return \ref axl_true if the list that is iterated can return data at
 1767:  * the current position, otherwise \ref axl_false is returned.
 1768:  */
 1769: axl_bool            axl_list_cursor_has_item    (axlListCursor * cursor)
 1770: {
 1771: 	axl_return_val_if_fail (cursor, axl_false);
 1772: 
 1773: 	/* return if there are current */
 1774: 	return (cursor->current != NULL);
 1775: }
 1776: 
 1777: /** 
 1778:  * @brief Allows to remove current element pointed by the cursor,
 1779:  * maintainig internal state of the cursor.
 1780:  *
 1781:  * The function won't call to the destroy function asociated to the
 1782:  * list. If you want the item stored to be also destroyed call \ref
 1783:  * axl_list_cursor_remove.
 1784:  * 
 1785:  * @param cursor The cursor pointing to the item inside the list that
 1786:  * must be removed.
 1787:  */
 1788: void            axl_list_cursor_unlink       (axlListCursor * cursor)
 1789: {
 1790: 	axlListNode * node;
 1791: 
 1792: 	axl_return_if_fail (cursor);
 1793: 
 1794: 	/* if current cursor is pointing nowhere, just do nothing */
 1795: 	if (cursor->current == NULL)
 1796: 		return;
 1797: 
 1798: 	/* remember node */
 1799: 	node = cursor->current;	
 1800: 
 1801: 	/* configure the cursor to point to the next element (or the previous if the next element is null) */
 1802: 	cursor->current = (node->next != NULL) ? node->next : node->previous;
 1803: 
 1804: 	/* call to unlik */
 1805: 	__axl_list_common_remove_selected_node (cursor->list, node, axl_false);
 1806: 
 1807: 	return;
 1808: }
 1809: 
 1810: /** 
 1811:  * @brief Allows to remove current element pointed by the cursor,
 1812:  * maintainig internal state of the cursor, calling to the destroy
 1813:  * function associated in the list.
 1814:  *
 1815:  * The function will call to the destroy function asociated to the
 1816:  * list. If you don't want the item stored to be also destroyed call \ref
 1817:  * axl_list_cursor_unlink.
 1818:  * 
 1819:  * @param cursor The cursor pointing to the item inside the list that
 1820:  * must be removed.
 1821:  */
 1822: void            axl_list_cursor_remove       (axlListCursor * cursor)
 1823: {
 1824: 	axlListNode * node;
 1825: 
 1826: 	axl_return_if_fail (cursor);
 1827: 
 1828: 	/* if current cursor is pointing nowhere, just do nothing */
 1829: 	if (cursor->current == NULL)
 1830: 		return;
 1831: 
 1832: 	/* remember node */
 1833: 	node = cursor->current;
 1834: 
 1835: 	/* configure the cursor to point to the next element (or the previous if the next element is null) */
 1836: 	cursor->current = (node->next != NULL) ? node->next : node->previous;
 1837: 
 1838: 	/* call to remove */
 1839: 	__axl_list_common_remove_selected_node (cursor->list, node, axl_true);
 1840: 
 1841: 	return;
 1842: }
 1843: 
 1844: /** 
 1845:  * @brief Allows to get current data at the current cursor state.
 1846:  * 
 1847:  * @param cursor The cursor that will be used to return the data
 1848:  * located at the list, using cursor current state.
 1849:  */
 1850: axlPointer      axl_list_cursor_get      (axlListCursor * cursor)
 1851: {
 1852: 	axl_return_val_if_fail (cursor, NULL);
 1853: 
 1854: 	/* nothing to return if current is NULL */
 1855: 	if (cursor->current == NULL)
 1856: 		return NULL;
 1857: 
 1858: 	/* return data */
 1859: 	return cursor->current->data;
 1860: }
 1861: 
 1862: /** 
 1863:  * @brief Allows to get the reference to the list that is associated
 1864:  * to the cursor received.
 1865:  * 
 1866:  * @param cursor The cursor that is required to return the list associated.
 1867:  * 
 1868:  * @return A reference to the list being iterated or NULL if fails.
 1869:  */
 1870: axlList       * axl_list_cursor_list         (axlListCursor * cursor)
 1871: {
 1872: 	/* check incoming cursor */
 1873: 	axl_return_val_if_fail (cursor, NULL);
 1874: 
 1875: 	/* return the list */
 1876: 	return cursor->list;
 1877: }
 1878: 
 1879: /** 
 1880:  * @brief Deallocates memory used by the cursor. 
 1881:  *
 1882:  * @param cursor The cursor to be deallocated.
 1883:  */
 1884: void            axl_list_cursor_free     (axlListCursor * cursor)
 1885: {
 1886: 	axl_return_if_fail (cursor);
 1887: 
 1888: 	/* free the cursor */
 1889: 	axl_free (cursor);
 1890: 
 1891: 	return;
 1892: }
 1893: 
 1894: /* @} */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>