Annotation of gpl/axl/src/axl_list.c, revision 1.1

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

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