Back to index

php5  5.3.10
queue.c
Go to the documentation of this file.
00001 static const char rcsid[] = "#(@) $Id: queue.c 87765 2002-07-05 04:43:55Z danda $";
00002 
00003 /* 
00004  * Date last modified: Jan 2001
00005  * Modifications by Dan Libby (dan@libby.com), including:
00006  *  - various fixes, null checks, etc
00007  *  - addition of Q_Iter funcs, macros
00008  */
00009 
00010 
00011 /*-**************************************************************
00012  *
00013  *  File : q.c
00014  *
00015  *  Author: Peter Yard [1993.01.02] -- 02 Jan 1993
00016  *
00017  *  Disclaimer: This code is released to the public domain.
00018  *
00019  *  Description:
00020  *      Generic double ended queue (Deque pronounced DEK) for handling
00021  *      any data types, with sorting.
00022  *
00023  *      By use of various functions in this module the caller
00024  *      can create stacks, queues, lists, doubly linked lists,
00025  *      sorted lists, indexed lists.  All lists are dynamic.
00026  *
00027  *      It is the responsibility of the caller to malloc and free
00028  *      memory for insertion into the queue. A pointer to the object
00029  *      is used so that not only can any data be used but various kinds
00030  *      of data can be pushed on the same queue if one so wished e.g.
00031  *      various length string literals mixed with pointers to structures
00032  *      or integers etc.
00033  *
00034  *  Enhancements:
00035  *      A future improvement would be the option of multiple "cursors"
00036  *      so that multiple locations could occur in the one queue to allow
00037  *      placemarkers and additional flexibility.  Perhaps even use queue
00038  *      itself to have a list of cursors.
00039  *
00040  * Usage:
00041  *
00042  *          /x init queue x/
00043  *          queue  q;
00044  *          Q_Init(&q);
00045  *
00046  *      To create a stack :
00047  *
00048  *          Q_PushHead(&q, &mydata1); /x push x/
00049  *          Q_PushHead(&q, &mydata2);
00050  *          .....
00051  *          data_ptr = Q_PopHead(&q); /x pop x/
00052  *          .....
00053  *          data_ptr = Q_Head(&q);   /x top of stack x/
00054  *
00055  *      To create a FIFO:
00056  *
00057  *          Q_PushHead(&q, &mydata1);
00058  *          .....
00059  *          data_ptr = Q_PopTail(&q);
00060  *
00061  *      To create a double list:
00062  *
00063  *          data_ptr = Q_Head(&q);
00064  *          ....
00065  *          data_ptr = Q_Next(&q);
00066  *          data_ptr = Q_Tail(&q);
00067  *          if (Q_IsEmpty(&q)) ....
00068  *          .....
00069  *          data_ptr = Q_Previous(&q);
00070  *
00071  *      To create a sorted list:
00072  *
00073  *          Q_PushHead(&q, &mydata1); /x push x/
00074  *          Q_PushHead(&q, &mydata2);
00075  *          .....
00076  *          if (!Q_Sort(&q, MyFunction))
00077  *              .. error ..
00078  *
00079  *          /x fill in key field of mydata1.
00080  *           * NB: Q_Find does linear search
00081  *           x/
00082  *
00083  *          if (Q_Find(&q, &mydata1, MyFunction))
00084  *          {
00085  *              /x found it, queue cursor now at correct record x/
00086  *              /x can retrieve with x/
00087  *              data_ptr = Q_Get(&q);
00088  *
00089  *              /x alter data , write back with x/
00090  *              Q_Put(&q, data_ptr);
00091  *          }
00092  *
00093  *          /x Search with binary search x/
00094  *          if (Q_Seek(&q, &mydata, MyFunction))
00095  *              /x etc x/
00096  *
00097  *
00098  ****************************************************************/
00099 
00100 #ifdef _WIN32
00101 #include "xmlrpc_win32.h"
00102 #endif
00103 #include <stdlib.h>
00104 #include "queue.h"
00105 
00106 
00107 static void QuickSort(void *list[], int low, int high,
00108                       int (*Comp)(const void *, const void *));
00109 static int  Q_BSearch(queue *q, void *key,
00110                       int (*Comp)(const void *, const void *));
00111 
00112 /* The index: a pointer to pointers */
00113 
00114 static  void        **index;
00115 static  datanode    **posn_index;
00116 
00117 
00118 /***
00119  *
00120  ** function    : Q_Init
00121  *
00122  ** purpose     : Initialise queue object and pointers.
00123  *
00124  ** parameters  : 'queue' pointer.
00125  *
00126  ** returns     : True_ if init successful else False_
00127  *
00128  ** comments    :
00129  ***/
00130 
00131 int Q_Init(queue  *q)
00132 {
00133    if(q) {
00134       q->head = q->tail = NULL;
00135       q->cursor = q->head;
00136       q->size = 0;
00137       q->sorted = False_;
00138    }
00139 
00140    return True_;
00141 }
00142 
00143 /***
00144  *
00145  ** function    : Q_AtHead
00146  *
00147  ** purpose     : tests if cursor is at head of queue
00148  *
00149  ** parameters  : 'queue' pointer.
00150  *
00151  ** returns     : boolean - True_ is at head else False_
00152  *
00153  ** comments    :
00154  *
00155  ***/
00156 
00157 int Q_AtHead(queue *q)
00158 {
00159    return(q && q->cursor == q->head);
00160 }
00161 
00162 
00163 /***
00164  *
00165  ** function    : Q_AtTail
00166  *
00167  ** purpose     : boolean test if cursor at tail of queue
00168  *
00169  ** parameters  : 'queue' pointer to test.
00170  *
00171  ** returns     : True_ or False_
00172  *
00173  ** comments    :
00174  *
00175  ***/
00176 
00177 int Q_AtTail(queue *q)
00178 {
00179    return(q && q->cursor == q->tail);
00180 }
00181 
00182 
00183 /***
00184  *
00185  ** function    : Q_IsEmpty
00186  *
00187  ** purpose     : test if queue has nothing in it.
00188  *
00189  ** parameters  : 'queue' pointer
00190  *
00191  ** returns     : True_ if IsEmpty queue, else False_
00192  *
00193  ** comments    :
00194  *
00195  ***/
00196 
00197 inline int Q_IsEmpty(queue *q)
00198 {
00199    return(!q || q->size == 0);
00200 }
00201 
00202 /***
00203  *
00204  ** function    : Q_Size
00205  *
00206  ** purpose     : return the number of elements in the queue
00207  *
00208  ** parameters  : queue pointer
00209  *
00210  ** returns     : number of elements
00211  *
00212  ** comments    :
00213  *
00214  ***/
00215 
00216 int Q_Size(queue *q)
00217 {
00218    return q ? q->size : 0;
00219 }
00220 
00221 
00222 /***
00223  *
00224  ** function    : Q_Head
00225  *
00226  ** purpose     : position queue cursor to first element (head) of queue.
00227  *
00228  ** parameters  : 'queue' pointer
00229  *
00230  ** returns     : pointer to data at head. If queue is IsEmpty returns NULL
00231  *
00232  ** comments    :
00233  *
00234  ***/
00235 
00236 void *Q_Head(queue *q)
00237 {
00238    if(Q_IsEmpty(q))
00239       return NULL;
00240 
00241    q->cursor = q->head;
00242 
00243    return  q->cursor->data;
00244 }
00245 
00246 
00247 /***
00248  *
00249  ** function    : Q_Tail
00250  *
00251  ** purpose     : locate cursor at tail of queue.
00252  *
00253  ** parameters  : 'queue' pointer
00254  *
00255  ** returns     : pointer to data at tail , if queue IsEmpty returns NULL
00256  *
00257  ** comments    :
00258  *
00259  ***/
00260 
00261 void *Q_Tail(queue *q)
00262 {
00263    if(Q_IsEmpty(q))
00264       return NULL;
00265 
00266    q->cursor = q->tail;
00267 
00268    return  q->cursor->data;
00269 }
00270 
00271 
00272 /***
00273  *
00274  ** function    : Q_PushHead
00275  *
00276  ** purpose     : put a data pointer at the head of the queue
00277  *
00278  ** parameters  : 'queue' pointer, void pointer to the data.
00279  *
00280  ** returns     : True_ if success else False_ if unable to push data.
00281  *
00282  ** comments    :
00283  *
00284  ***/
00285 
00286 int Q_PushHead(queue *q, void *d)
00287 {
00288    if(q && d) {
00289       node    *n;
00290       datanode *p;
00291 
00292       p = malloc(sizeof(datanode));
00293       if(p == NULL)
00294          return False_;
00295 
00296       n = q->head;
00297 
00298       q->head = (node*)p;
00299       q->head->prev = NULL;
00300 
00301       if(q->size == 0) {
00302          q->head->next = NULL;
00303          q->tail = q->head;
00304       }
00305       else {
00306          q->head->next = (datanode*)n;
00307          n->prev = q->head;
00308       }
00309 
00310       q->head->data = d;
00311       q->size++;
00312 
00313       q->cursor = q->head;
00314 
00315       q->sorted = False_;
00316 
00317       return True_;
00318    }
00319    return False_;
00320 }
00321 
00322 
00323 
00324 /***
00325  *
00326  ** function    : Q_PushTail
00327  *
00328  ** purpose     : put a data element pointer at the tail of the queue
00329  *
00330  ** parameters  : queue pointer, pointer to the data
00331  *
00332  ** returns     : True_ if data pushed, False_ if data not inserted.
00333  *
00334  ** comments    :
00335  *
00336  ***/
00337 
00338 int Q_PushTail(queue *q, void *d)
00339 {
00340    if(q && d) {
00341       node        *p;
00342       datanode    *n;
00343 
00344       n = malloc(sizeof(datanode));
00345       if(n == NULL)
00346          return False_;
00347 
00348       p = q->tail;
00349       q->tail = (node *)n;
00350 
00351       if(q->size == 0) {
00352          q->tail->prev = NULL;
00353          q->head = q->tail;
00354       }
00355       else {
00356          q->tail->prev = (datanode *)p;
00357          p->next = q->tail;
00358       }
00359 
00360       q->tail->next = NULL;
00361 
00362       q->tail->data =  d;
00363       q->cursor = q->tail;
00364       q->size++;
00365 
00366       q->sorted = False_;
00367 
00368       return True_;
00369    }
00370    return False_;
00371 }
00372 
00373 
00374 
00375 /***
00376  *
00377  ** function    : Q_PopHead
00378  *
00379  ** purpose     : remove and return the top element at the head of the
00380  *                queue.
00381  *
00382  ** parameters  : queue pointer
00383  *
00384  ** returns     : pointer to data element or NULL if queue is IsEmpty.
00385  *
00386  ** comments    :
00387  *
00388  ***/
00389 
00390 void *Q_PopHead(queue *q)
00391 {
00392    datanode    *n;
00393    void        *d;
00394 
00395    if(Q_IsEmpty(q))
00396       return NULL;
00397 
00398    d = q->head->data;
00399    n = q->head->next;
00400    free(q->head);
00401 
00402    q->size--;
00403 
00404    if(q->size == 0)
00405       q->head = q->tail = q->cursor = NULL;
00406    else {
00407       q->head = (node *)n;
00408       q->head->prev = NULL;
00409       q->cursor = q->head;
00410    }
00411 
00412    q->sorted = False_;
00413 
00414    return d;
00415 }
00416 
00417 
00418 /***
00419  *
00420  ** function    : Q_PopTail
00421  *
00422  ** purpose     : remove element from tail of queue and return data.
00423  *
00424  ** parameters  : queue pointer
00425  *
00426  ** returns     : pointer to data element that was at tail. NULL if queue
00427  *                IsEmpty.
00428  *
00429  ** comments    :
00430  *
00431  ***/
00432 
00433 void *Q_PopTail(queue *q)
00434 {
00435    datanode    *p;
00436    void        *d;
00437 
00438    if(Q_IsEmpty(q))
00439       return NULL;
00440 
00441    d = q->tail->data;
00442    p = q->tail->prev;
00443    free(q->tail);
00444    q->size--;
00445 
00446    if(q->size == 0)
00447       q->head = q->tail = q->cursor = NULL;
00448    else {
00449       q->tail = (node *)p;
00450       q->tail->next = NULL;
00451       q->cursor = q->tail;
00452    }
00453 
00454    q->sorted = False_;
00455 
00456    return d;
00457 }
00458 
00459 
00460 
00461 /***
00462  *
00463  ** function    : Q_Next
00464  *
00465  ** purpose     : Move to the next element in the queue without popping
00466  *
00467  ** parameters  : queue pointer.
00468  *
00469  ** returns     : pointer to data element of new element or NULL if end
00470  *                of the queue.
00471  *
00472  ** comments    : This uses the cursor for the current position. Q_Next
00473  *                only moves in the direction from the head of the queue
00474  *                to the tail.
00475  ***/
00476 
00477 void *Q_Next(queue *q)
00478 {
00479    if(!q)
00480       return NULL;
00481 
00482    if(!q->cursor || q->cursor->next == NULL)
00483       return NULL;
00484 
00485    q->cursor = (node *)q->cursor->next;
00486 
00487    return  q->cursor->data ;
00488 }
00489 
00490 
00491 
00492 /***
00493  *
00494  ** function    : Q_Previous
00495  *
00496  ** purpose     : Opposite of Q_Next. Move to next element closer to the
00497  *                head of the queue.
00498  *
00499  ** parameters  : pointer to queue
00500  *
00501  ** returns     : pointer to data of new element else NULL if queue IsEmpty
00502  *
00503  ** comments    : Makes cursor move towards the head of the queue.
00504  *
00505  ***/
00506 
00507 void *Q_Previous(queue *q)
00508 {
00509    if(!q)
00510       return NULL;
00511    
00512    if(q->cursor->prev == NULL)
00513       return NULL;
00514 
00515    q->cursor = (node *)q->cursor->prev;
00516 
00517    return q->cursor->data;
00518 }
00519 
00520 
00521 void *Q_Iter_Del(queue *q, q_iter iter)
00522 {
00523    void        *d;
00524    datanode    *n, *p;
00525 
00526    if(!q)
00527       return NULL;
00528 
00529    if(iter == NULL)
00530       return NULL;
00531 
00532    if(iter == (q_iter)q->head)
00533       return Q_PopHead(q);
00534 
00535    if(iter == (q_iter)q->tail)
00536       return Q_PopTail(q);
00537 
00538    n = ((node*)iter)->next;
00539    p = ((node*)iter)->prev;
00540    d = ((node*)iter)->data;
00541 
00542    free(iter);
00543 
00544    if(p) {
00545       p->next = n;
00546    }
00547    if (q->cursor == (node*)iter) {
00548       if (p) {
00549          q->cursor = p;
00550       } else {
00551          q->cursor = n;
00552       }
00553    }
00554 
00555 
00556    if (n != NULL) {
00557        n->prev = p;
00558    }
00559 
00560    q->size--;
00561 
00562    q->sorted = False_;
00563 
00564    return d;
00565 }
00566 
00567 
00568 
00569 /***
00570  *
00571  ** function    : Q_DelCur
00572  *
00573  ** purpose     : Delete the current queue element as pointed to by
00574  *                the cursor.
00575  *
00576  ** parameters  : queue pointer
00577  *
00578  ** returns     : pointer to data element.
00579  *
00580  ** comments    : WARNING! It is the responsibility of the caller to
00581  *                free any memory. Queue cannot distinguish between
00582  *                pointers to literals and malloced memory.
00583  *
00584  ***/
00585 
00586 void *Q_DelCur(queue* q) {
00587    if(q) {
00588       return Q_Iter_Del(q, (q_iter)q->cursor);
00589    }
00590    return 0;
00591 }
00592 
00593 
00594 /***
00595  *
00596  ** function    : Q_Destroy
00597  *
00598  ** purpose     : Free all queue resources
00599  *
00600  ** parameters  : queue pointer
00601  *
00602  ** returns     : null.
00603  *
00604  ** comments    : WARNING! It is the responsibility of the caller to
00605  *                free any memory. Queue cannot distinguish between
00606  *                pointers to literals and malloced memory.
00607  *
00608  ***/
00609 
00610 void Q_Destroy(queue *q)
00611 {
00612    while(!Q_IsEmpty(q)) {
00613       Q_PopHead(q);
00614    }
00615 }
00616 
00617 
00618 /***
00619  *
00620  ** function    : Q_Get
00621  *
00622  ** purpose     : get the pointer to the data at the cursor location
00623  *
00624  ** parameters  : queue pointer
00625  *
00626  ** returns     : data element pointer
00627  *
00628  ** comments    :
00629  *
00630  ***/
00631 
00632 void *Q_Get(queue *q)
00633 {
00634    if(!q)
00635       return NULL;
00636 
00637    if(q->cursor == NULL)
00638       return NULL;
00639    return q->cursor->data;
00640 }
00641 
00642 
00643 
00644 /***
00645  *
00646  ** function    : Q_Put
00647  *
00648  ** purpose     : replace pointer to data with new pointer to data.
00649  *
00650  ** parameters  : queue pointer, data pointer
00651  *
00652  ** returns     : boolean- True_ if successful, False_ if cursor at NULL
00653  *
00654  ** comments    :
00655  *
00656  ***/
00657 
00658 int Q_Put(queue *q, void *data)
00659 {
00660    if(q && data) {
00661       if(q->cursor == NULL)
00662          return False_;
00663 
00664       q->cursor->data = data;
00665       return True_;
00666    }
00667    return False_;
00668 }
00669 
00670 
00671 /***
00672  *
00673  ** function    : Q_Find
00674  *
00675  ** purpose     : Linear search of queue for match with key in *data
00676  *
00677  ** parameters  : queue pointer q, data pointer with data containing key
00678  *                comparison function here called Comp.
00679  *
00680  ** returns     : True_ if found , False_ if not in queue.
00681  *
00682  ** comments    : Useful for small queues that are constantly changing
00683  *                and would otherwise need constant sorting with the
00684  *                Q_Seek function.
00685  *                For description of Comp see Q_Sort.
00686  *                Queue cursor left on position found item else at end.
00687  *
00688  ***/
00689 
00690 int Q_Find(queue *q, void *data,
00691            int (*Comp)(const void *, const void *))
00692 {
00693    void *d;
00694 
00695    if (q == NULL) {
00696        return False_;
00697    }
00698 
00699    d = Q_Head(q);
00700    do {
00701       if(Comp(d, data) == 0)
00702          return True_;
00703       d = Q_Next(q);
00704    } while(!Q_AtTail(q));
00705 
00706    if(Comp(d, data) == 0)
00707       return True_;
00708 
00709    return False_;
00710 }
00711 
00712 /*========  Sorted Queue and Index functions   ========= */
00713 
00714 
00715 static void QuickSort(void *list[], int low, int high,
00716                       int (*Comp)(const void *, const void *))
00717 {
00718    int     flag = 1, i, j;
00719    void    *key, *temp;
00720 
00721    if(low < high) {
00722       i = low;
00723       j = high + 1;
00724 
00725       key = list[ low ];
00726 
00727       while(flag) {
00728          i++;
00729          while(Comp(list[i], key) < 0)
00730             i++;
00731 
00732          j--;
00733          while(Comp(list[j], key) > 0)
00734             j--;
00735 
00736          if(i < j) {
00737             temp = list[i];
00738             list[i] = list[j];
00739             list[j] = temp;
00740          }
00741          else  flag = 0;
00742       }
00743 
00744       temp = list[low];
00745       list[low] = list[j];
00746       list[j] = temp;
00747 
00748       QuickSort(list, low, j-1, Comp);
00749       QuickSort(list, j+1, high, Comp);
00750    }
00751 }
00752 
00753 
00754 /***
00755  *
00756  ** function    : Q_Sort
00757  *
00758  ** purpose     : sort the queue and allow index style access.
00759  *
00760  ** parameters  : queue pointer, comparison function compatible with
00761  *                with 'qsort'.
00762  *
00763  ** returns     : True_ if sort succeeded. False_ if error occurred.
00764  *
00765  ** comments    : Comp function supplied by caller must return
00766  *                  -1 if data1  < data2
00767  *                   0 if data1 == data2
00768  *                  +1 if data1  > data2
00769  *
00770  *                    for Comp(data1, data2)
00771  *
00772  *                If queue is already sorted it frees the memory of the
00773  *                old index and starts again.
00774  *
00775  ***/
00776 
00777 int Q_Sort(queue *q, int (*Comp)(const void *, const void *))
00778 {
00779    int         i;
00780    void        *d;
00781    datanode    *dn;
00782 
00783    /* if already sorted free memory for tag array */
00784 
00785    if(q->sorted) {
00786       free(index);
00787       free(posn_index);
00788       q->sorted = False_;
00789    }
00790 
00791    /* Now allocate memory of array, array of pointers */
00792 
00793    index = malloc(q->size * sizeof(q->cursor->data));
00794    if(index == NULL)
00795       return False_;
00796 
00797    posn_index = malloc(q->size * sizeof(q->cursor));
00798    if(posn_index == NULL) {
00799       free(index);
00800       return False_;
00801    }
00802 
00803    /* Walk queue putting pointers into array */
00804 
00805    d = Q_Head(q);
00806    for(i=0; i < q->size; i++) {
00807       index[i] = d;
00808       posn_index[i] = q->cursor;
00809       d = Q_Next(q);
00810    }
00811 
00812    /* Now sort the index */
00813 
00814    QuickSort(index, 0, q->size - 1, Comp);
00815 
00816    /* Rearrange the actual queue into correct order */
00817 
00818    dn = q->head;
00819    i = 0;
00820    while(dn != NULL) {
00821       dn->data = index[i++];
00822       dn = dn->next;
00823    }
00824 
00825    /* Re-position to original element */
00826 
00827    if(d != NULL)
00828       Q_Find(q, d, Comp);
00829    else  Q_Head(q);
00830 
00831    q->sorted = True_;
00832 
00833    return True_;
00834 }
00835 
00836 
00837 /***
00838  *
00839  ** function    : Q_BSearch
00840  *
00841  ** purpose     : binary search of queue index for node containing key
00842  *
00843  ** parameters  : queue pointer 'q', data pointer of key 'key',
00844  *                  Comp comparison function.
00845  *
00846  ** returns     : integer index into array of node pointers,
00847  *                or -1 if not found.
00848  *
00849  ** comments    : see Q_Sort for description of 'Comp' function.
00850  *
00851  ***/
00852 
00853 static int Q_BSearch( queue *q, void *key,
00854                       int (*Comp)(const void *, const void*))
00855 {
00856    int low, mid, hi, val;
00857 
00858    low = 0;
00859    hi = q->size - 1;
00860 
00861    while(low <= hi) {
00862       mid = (low + hi) / 2;
00863       val = Comp(key, index[ mid ]);
00864 
00865       if(val < 0)
00866          hi = mid - 1;
00867 
00868       else if(val > 0)
00869          low = mid + 1;
00870 
00871       else /* Success */
00872          return mid;
00873    }
00874 
00875    /* Not Found */
00876 
00877    return -1;
00878 }
00879 
00880 
00881 /***
00882  *
00883  ** function    : Q_Seek
00884  *
00885  ** purpose     : use index to locate data according to key in 'data'
00886  *
00887  ** parameters  : queue pointer 'q', data pointer 'data', Comp comparison
00888  *                function.
00889  *
00890  ** returns     : pointer to data or NULL if could not find it or could
00891  *                not sort queue.
00892  *
00893  ** comments    : see Q_Sort for description of 'Comp' function.
00894  *
00895  ***/
00896 
00897 void *Q_Seek(queue *q, void *data, int (*Comp)(const void *, const void *))
00898 {
00899    int idx;
00900 
00901    if (q == NULL) {
00902        return NULL;
00903    }
00904 
00905    if(!q->sorted) {
00906       if(!Q_Sort(q, Comp))
00907          return NULL;
00908    }
00909 
00910    idx = Q_BSearch(q, data, Comp);
00911 
00912    if(idx < 0)
00913       return NULL;
00914 
00915    q->cursor = posn_index[idx];
00916 
00917    return index[idx];
00918 }
00919 
00920 
00921 
00922 /***
00923  *
00924  ** function    : Q_Insert
00925  *
00926  ** purpose     : Insert an element into an indexed queue
00927  *
00928  ** parameters  : queue pointer 'q', data pointer 'data', Comp comparison
00929  *                function.
00930  *
00931  ** returns     : pointer to data or NULL if could not find it or could
00932  *                not sort queue.
00933  *
00934  ** comments    : see Q_Sort for description of 'Comp' function.
00935  *                WARNING! This code can be very slow since each new
00936  *                element means a new Q_Sort.  Should only be used for
00937  *                the insertion of the odd element ,not the piecemeal
00938  *                building of an entire queue.
00939  ***/
00940 
00941 int Q_Insert(queue *q, void *data, int (*Comp)(const void *, const void *))
00942 {
00943    if (q == NULL) {
00944        return False_;
00945    }
00946 
00947    Q_PushHead(q, data);
00948 
00949    if(!Q_Sort(q, Comp))
00950       return False_;
00951 
00952    return True_;
00953 }
00954 
00955 /* read only funcs for iterating through queue. above funcs modify queue */
00956 q_iter Q_Iter_Head(queue *q) {
00957    return q ? (q_iter)q->head : NULL;
00958 }
00959 
00960 q_iter Q_Iter_Tail(queue *q) {
00961    return q ? (q_iter)q->tail : NULL;
00962 }
00963 
00964 q_iter Q_Iter_Next(q_iter qi) {
00965    return qi ? (q_iter)((node*)qi)->next : NULL;
00966 }
00967 
00968 q_iter Q_Iter_Prev(q_iter qi) {
00969    return qi ? (q_iter)((node*)qi)->prev : NULL;
00970 }
00971 
00972 void * Q_Iter_Get(q_iter qi) {
00973    return qi ? ((node*)qi)->data : NULL;
00974 }
00975 
00976 int Q_Iter_Put(q_iter qi, void* data) {
00977    if(qi) {
00978       ((node*)qi)->data = data;
00979       return True_;
00980    }
00981    return False_;
00982 }