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

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

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