queue.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. static const char rcsid[] = "#(@) $Id$";
  2. /*
  3. * Date last modified: Jan 2001
  4. * Modifications by Dan Libby (dan@libby.com), including:
  5. * - various fixes, null checks, etc
  6. * - addition of Q_Iter funcs, macros
  7. */
  8. /*-**************************************************************
  9. *
  10. * File : q.c
  11. *
  12. * Author: Peter Yard [1993.01.02] -- 02 Jan 1993
  13. *
  14. * Disclaimer: This code is released to the public domain.
  15. *
  16. * Description:
  17. * Generic double ended queue (Deque pronounced DEK) for handling
  18. * any data types, with sorting.
  19. *
  20. * By use of various functions in this module the caller
  21. * can create stacks, queues, lists, doubly linked lists,
  22. * sorted lists, indexed lists. All lists are dynamic.
  23. *
  24. * It is the responsibility of the caller to malloc and free
  25. * memory for insertion into the queue. A pointer to the object
  26. * is used so that not only can any data be used but various kinds
  27. * of data can be pushed on the same queue if one so wished e.g.
  28. * various length string literals mixed with pointers to structures
  29. * or integers etc.
  30. *
  31. * Enhancements:
  32. * A future improvement would be the option of multiple "cursors"
  33. * so that multiple locations could occur in the one queue to allow
  34. * placemarkers and additional flexibility. Perhaps even use queue
  35. * itself to have a list of cursors.
  36. *
  37. * Usage:
  38. *
  39. * /x init queue x/
  40. * queue q;
  41. * Q_Init(&q);
  42. *
  43. * To create a stack :
  44. *
  45. * Q_PushHead(&q, &mydata1); /x push x/
  46. * Q_PushHead(&q, &mydata2);
  47. * .....
  48. * data_ptr = Q_PopHead(&q); /x pop x/
  49. * .....
  50. * data_ptr = Q_Head(&q); /x top of stack x/
  51. *
  52. * To create a FIFO:
  53. *
  54. * Q_PushHead(&q, &mydata1);
  55. * .....
  56. * data_ptr = Q_PopTail(&q);
  57. *
  58. * To create a double list:
  59. *
  60. * data_ptr = Q_Head(&q);
  61. * ....
  62. * data_ptr = Q_Next(&q);
  63. * data_ptr = Q_Tail(&q);
  64. * if (Q_IsEmpty(&q)) ....
  65. * .....
  66. * data_ptr = Q_Previous(&q);
  67. *
  68. * To create a sorted list:
  69. *
  70. * Q_PushHead(&q, &mydata1); /x push x/
  71. * Q_PushHead(&q, &mydata2);
  72. * .....
  73. * if (!Q_Sort(&q, MyFunction))
  74. * .. error ..
  75. *
  76. * /x fill in key field of mydata1.
  77. * * NB: Q_Find does linear search
  78. * x/
  79. *
  80. * if (Q_Find(&q, &mydata1, MyFunction))
  81. * {
  82. * /x found it, queue cursor now at correct record x/
  83. * /x can retrieve with x/
  84. * data_ptr = Q_Get(&q);
  85. *
  86. * /x alter data , write back with x/
  87. * Q_Put(&q, data_ptr);
  88. * }
  89. *
  90. * /x Search with binary search x/
  91. * if (Q_Seek(&q, &mydata, MyFunction))
  92. * /x etc x/
  93. *
  94. *
  95. ****************************************************************/
  96. #include <stdlib.h>
  97. #include <php.h>
  98. #include "queue.h"
  99. static void QuickSort(void *list[], int low, int high,
  100. int (*Comp)(const void *, const void *));
  101. static int Q_BSearch(queue *q, void *key,
  102. int (*Comp)(const void *, const void *));
  103. /* The index: a pointer to pointers */
  104. static void **queue_index;
  105. static datanode **queue_posn_index;
  106. /***
  107. *
  108. ** function : Q_Init
  109. *
  110. ** purpose : Initialise queue object and pointers.
  111. *
  112. ** parameters : 'queue' pointer.
  113. *
  114. ** returns : True_ if init successful else False_
  115. *
  116. ** comments :
  117. ***/
  118. int Q_Init(queue *q)
  119. {
  120. if(q) {
  121. q->head = q->tail = NULL;
  122. q->cursor = q->head;
  123. q->size = 0;
  124. q->sorted = False_;
  125. }
  126. return True_;
  127. }
  128. /***
  129. *
  130. ** function : Q_AtHead
  131. *
  132. ** purpose : tests if cursor is at head of queue
  133. *
  134. ** parameters : 'queue' pointer.
  135. *
  136. ** returns : boolean - True_ is at head else False_
  137. *
  138. ** comments :
  139. *
  140. ***/
  141. int Q_AtHead(queue *q)
  142. {
  143. return(q && q->cursor == q->head);
  144. }
  145. /***
  146. *
  147. ** function : Q_AtTail
  148. *
  149. ** purpose : boolean test if cursor at tail of queue
  150. *
  151. ** parameters : 'queue' pointer to test.
  152. *
  153. ** returns : True_ or False_
  154. *
  155. ** comments :
  156. *
  157. ***/
  158. int Q_AtTail(queue *q)
  159. {
  160. return(q && q->cursor == q->tail);
  161. }
  162. /***
  163. *
  164. ** function : Q_IsEmpty
  165. *
  166. ** purpose : test if queue has nothing in it.
  167. *
  168. ** parameters : 'queue' pointer
  169. *
  170. ** returns : True_ if IsEmpty queue, else False_
  171. *
  172. ** comments :
  173. *
  174. ***/
  175. inline int Q_IsEmpty(queue *q)
  176. {
  177. return(!q || q->size == 0);
  178. }
  179. /***
  180. *
  181. ** function : Q_Size
  182. *
  183. ** purpose : return the number of elements in the queue
  184. *
  185. ** parameters : queue pointer
  186. *
  187. ** returns : number of elements
  188. *
  189. ** comments :
  190. *
  191. ***/
  192. int Q_Size(queue *q)
  193. {
  194. return q ? q->size : 0;
  195. }
  196. /***
  197. *
  198. ** function : Q_Head
  199. *
  200. ** purpose : position queue cursor to first element (head) of queue.
  201. *
  202. ** parameters : 'queue' pointer
  203. *
  204. ** returns : pointer to data at head. If queue is IsEmpty returns NULL
  205. *
  206. ** comments :
  207. *
  208. ***/
  209. void *Q_Head(queue *q)
  210. {
  211. if(Q_IsEmpty(q))
  212. return NULL;
  213. q->cursor = q->head;
  214. return q->cursor->data;
  215. }
  216. /***
  217. *
  218. ** function : Q_Tail
  219. *
  220. ** purpose : locate cursor at tail of queue.
  221. *
  222. ** parameters : 'queue' pointer
  223. *
  224. ** returns : pointer to data at tail , if queue IsEmpty returns NULL
  225. *
  226. ** comments :
  227. *
  228. ***/
  229. void *Q_Tail(queue *q)
  230. {
  231. if(Q_IsEmpty(q))
  232. return NULL;
  233. q->cursor = q->tail;
  234. return q->cursor->data;
  235. }
  236. /***
  237. *
  238. ** function : Q_PushHead
  239. *
  240. ** purpose : put a data pointer at the head of the queue
  241. *
  242. ** parameters : 'queue' pointer, void pointer to the data.
  243. *
  244. ** returns : True_ if success else False_ if unable to push data.
  245. *
  246. ** comments :
  247. *
  248. ***/
  249. int Q_PushHead(queue *q, void *d)
  250. {
  251. if(q && d) {
  252. node *n;
  253. datanode *p;
  254. p = emalloc(sizeof(datanode));
  255. if(p == NULL)
  256. return False_;
  257. n = q->head;
  258. q->head = (node*)p;
  259. q->head->prev = NULL;
  260. if(q->size == 0) {
  261. q->head->next = NULL;
  262. q->tail = q->head;
  263. }
  264. else {
  265. q->head->next = (datanode*)n;
  266. n->prev = q->head;
  267. }
  268. q->head->data = d;
  269. q->size++;
  270. q->cursor = q->head;
  271. q->sorted = False_;
  272. return True_;
  273. }
  274. return False_;
  275. }
  276. /***
  277. *
  278. ** function : Q_PushTail
  279. *
  280. ** purpose : put a data element pointer at the tail of the queue
  281. *
  282. ** parameters : queue pointer, pointer to the data
  283. *
  284. ** returns : True_ if data pushed, False_ if data not inserted.
  285. *
  286. ** comments :
  287. *
  288. ***/
  289. int Q_PushTail(queue *q, void *d)
  290. {
  291. if(q && d) {
  292. node *p;
  293. datanode *n;
  294. n = emalloc(sizeof(datanode));
  295. if(n == NULL)
  296. return False_;
  297. p = q->tail;
  298. q->tail = (node *)n;
  299. if(q->size == 0) {
  300. q->tail->prev = NULL;
  301. q->head = q->tail;
  302. }
  303. else {
  304. q->tail->prev = (datanode *)p;
  305. p->next = q->tail;
  306. }
  307. q->tail->next = NULL;
  308. q->tail->data = d;
  309. q->cursor = q->tail;
  310. q->size++;
  311. q->sorted = False_;
  312. return True_;
  313. }
  314. return False_;
  315. }
  316. /***
  317. *
  318. ** function : Q_PopHead
  319. *
  320. ** purpose : remove and return the top element at the head of the
  321. * queue.
  322. *
  323. ** parameters : queue pointer
  324. *
  325. ** returns : pointer to data element or NULL if queue is IsEmpty.
  326. *
  327. ** comments :
  328. *
  329. ***/
  330. void *Q_PopHead(queue *q)
  331. {
  332. datanode *n;
  333. void *d;
  334. if(Q_IsEmpty(q))
  335. return NULL;
  336. d = q->head->data;
  337. n = q->head->next;
  338. efree(q->head);
  339. q->size--;
  340. if(q->size == 0)
  341. q->head = q->tail = q->cursor = NULL;
  342. else {
  343. q->head = (node *)n;
  344. q->head->prev = NULL;
  345. q->cursor = q->head;
  346. }
  347. q->sorted = False_;
  348. return d;
  349. }
  350. /***
  351. *
  352. ** function : Q_PopTail
  353. *
  354. ** purpose : remove element from tail of queue and return data.
  355. *
  356. ** parameters : queue pointer
  357. *
  358. ** returns : pointer to data element that was at tail. NULL if queue
  359. * IsEmpty.
  360. *
  361. ** comments :
  362. *
  363. ***/
  364. void *Q_PopTail(queue *q)
  365. {
  366. datanode *p;
  367. void *d;
  368. if(Q_IsEmpty(q))
  369. return NULL;
  370. d = q->tail->data;
  371. p = q->tail->prev;
  372. efree(q->tail);
  373. q->size--;
  374. if(q->size == 0)
  375. q->head = q->tail = q->cursor = NULL;
  376. else {
  377. q->tail = (node *)p;
  378. q->tail->next = NULL;
  379. q->cursor = q->tail;
  380. }
  381. q->sorted = False_;
  382. return d;
  383. }
  384. /***
  385. *
  386. ** function : Q_Next
  387. *
  388. ** purpose : Move to the next element in the queue without popping
  389. *
  390. ** parameters : queue pointer.
  391. *
  392. ** returns : pointer to data element of new element or NULL if end
  393. * of the queue.
  394. *
  395. ** comments : This uses the cursor for the current position. Q_Next
  396. * only moves in the direction from the head of the queue
  397. * to the tail.
  398. ***/
  399. void *Q_Next(queue *q)
  400. {
  401. if(!q)
  402. return NULL;
  403. if(!q->cursor || q->cursor->next == NULL)
  404. return NULL;
  405. q->cursor = (node *)q->cursor->next;
  406. return q->cursor->data ;
  407. }
  408. /***
  409. *
  410. ** function : Q_Previous
  411. *
  412. ** purpose : Opposite of Q_Next. Move to next element closer to the
  413. * head of the queue.
  414. *
  415. ** parameters : pointer to queue
  416. *
  417. ** returns : pointer to data of new element else NULL if queue IsEmpty
  418. *
  419. ** comments : Makes cursor move towards the head of the queue.
  420. *
  421. ***/
  422. void *Q_Previous(queue *q)
  423. {
  424. if(!q)
  425. return NULL;
  426. if(q->cursor->prev == NULL)
  427. return NULL;
  428. q->cursor = (node *)q->cursor->prev;
  429. return q->cursor->data;
  430. }
  431. void *Q_Iter_Del(queue *q, q_iter iter)
  432. {
  433. void *d;
  434. datanode *n, *p;
  435. if(!q)
  436. return NULL;
  437. if(iter == NULL)
  438. return NULL;
  439. if(iter == (q_iter)q->head)
  440. return Q_PopHead(q);
  441. if(iter == (q_iter)q->tail)
  442. return Q_PopTail(q);
  443. n = ((node*)iter)->next;
  444. p = ((node*)iter)->prev;
  445. d = ((node*)iter)->data;
  446. efree(iter);
  447. if(p) {
  448. p->next = n;
  449. }
  450. if (q->cursor == (node*)iter) {
  451. if (p) {
  452. q->cursor = p;
  453. } else {
  454. q->cursor = n;
  455. }
  456. }
  457. if (n != NULL) {
  458. n->prev = p;
  459. }
  460. q->size--;
  461. q->sorted = False_;
  462. return d;
  463. }
  464. /***
  465. *
  466. ** function : Q_DelCur
  467. *
  468. ** purpose : Delete the current queue element as pointed to by
  469. * the cursor.
  470. *
  471. ** parameters : queue pointer
  472. *
  473. ** returns : pointer to data element.
  474. *
  475. ** comments : WARNING! It is the responsibility of the caller to
  476. * free any memory. Queue cannot distinguish between
  477. * pointers to literals and malloced memory.
  478. *
  479. ***/
  480. void *Q_DelCur(queue* q) {
  481. if(q) {
  482. return Q_Iter_Del(q, (q_iter)q->cursor);
  483. }
  484. return 0;
  485. }
  486. /***
  487. *
  488. ** function : Q_Destroy
  489. *
  490. ** purpose : Free all queue resources
  491. *
  492. ** parameters : queue pointer
  493. *
  494. ** returns : null.
  495. *
  496. ** comments : WARNING! It is the responsibility of the caller to
  497. * free any memory. Queue cannot distinguish between
  498. * pointers to literals and malloced memory.
  499. *
  500. ***/
  501. void Q_Destroy(queue *q)
  502. {
  503. while(!Q_IsEmpty(q)) {
  504. Q_PopHead(q);
  505. }
  506. }
  507. /***
  508. *
  509. ** function : Q_Get
  510. *
  511. ** purpose : get the pointer to the data at the cursor location
  512. *
  513. ** parameters : queue pointer
  514. *
  515. ** returns : data element pointer
  516. *
  517. ** comments :
  518. *
  519. ***/
  520. void *Q_Get(queue *q)
  521. {
  522. if(!q)
  523. return NULL;
  524. if(q->cursor == NULL)
  525. return NULL;
  526. return q->cursor->data;
  527. }
  528. /***
  529. *
  530. ** function : Q_Put
  531. *
  532. ** purpose : replace pointer to data with new pointer to data.
  533. *
  534. ** parameters : queue pointer, data pointer
  535. *
  536. ** returns : boolean- True_ if successful, False_ if cursor at NULL
  537. *
  538. ** comments :
  539. *
  540. ***/
  541. int Q_Put(queue *q, void *data)
  542. {
  543. if(q && data) {
  544. if(q->cursor == NULL)
  545. return False_;
  546. q->cursor->data = data;
  547. return True_;
  548. }
  549. return False_;
  550. }
  551. /***
  552. *
  553. ** function : Q_Find
  554. *
  555. ** purpose : Linear search of queue for match with key in *data
  556. *
  557. ** parameters : queue pointer q, data pointer with data containing key
  558. * comparison function here called Comp.
  559. *
  560. ** returns : True_ if found , False_ if not in queue.
  561. *
  562. ** comments : Useful for small queues that are constantly changing
  563. * and would otherwise need constant sorting with the
  564. * Q_Seek function.
  565. * For description of Comp see Q_Sort.
  566. * Queue cursor left on position found item else at end.
  567. *
  568. ***/
  569. int Q_Find(queue *q, void *data,
  570. int (*Comp)(const void *, const void *))
  571. {
  572. void *d;
  573. if (q == NULL) {
  574. return False_;
  575. }
  576. d = Q_Head(q);
  577. do {
  578. if(Comp(d, data) == 0)
  579. return True_;
  580. d = Q_Next(q);
  581. } while(!Q_AtTail(q));
  582. if(Comp(d, data) == 0)
  583. return True_;
  584. return False_;
  585. }
  586. /*======== Sorted Queue and Index functions ========= */
  587. static void QuickSort(void *list[], int low, int high,
  588. int (*Comp)(const void *, const void *))
  589. {
  590. int flag = 1, i, j;
  591. void *key, *temp;
  592. if(low < high) {
  593. i = low;
  594. j = high + 1;
  595. key = list[ low ];
  596. while(flag) {
  597. i++;
  598. while(Comp(list[i], key) < 0)
  599. i++;
  600. j--;
  601. while(Comp(list[j], key) > 0)
  602. j--;
  603. if(i < j) {
  604. temp = list[i];
  605. list[i] = list[j];
  606. list[j] = temp;
  607. }
  608. else flag = 0;
  609. }
  610. temp = list[low];
  611. list[low] = list[j];
  612. list[j] = temp;
  613. QuickSort(list, low, j-1, Comp);
  614. QuickSort(list, j+1, high, Comp);
  615. }
  616. }
  617. /***
  618. *
  619. ** function : Q_Sort
  620. *
  621. ** purpose : sort the queue and allow index style access.
  622. *
  623. ** parameters : queue pointer, comparison function compatible with
  624. * with 'qsort'.
  625. *
  626. ** returns : True_ if sort succeeded. False_ if error occurred.
  627. *
  628. ** comments : Comp function supplied by caller must return
  629. * -1 if data1 < data2
  630. * 0 if data1 == data2
  631. * +1 if data1 > data2
  632. *
  633. * for Comp(data1, data2)
  634. *
  635. * If queue is already sorted it frees the memory of the
  636. * old index and starts again.
  637. *
  638. ***/
  639. int Q_Sort(queue *q, int (*Comp)(const void *, const void *))
  640. {
  641. int i;
  642. void *d;
  643. datanode *dn;
  644. /* if already sorted free memory for tag array */
  645. if(q->sorted) {
  646. efree(queue_index);
  647. efree(queue_posn_index);
  648. q->sorted = False_;
  649. }
  650. /* Now allocate memory of array, array of pointers */
  651. queue_index = emalloc(q->size * sizeof(q->cursor->data));
  652. if(queue_index == NULL)
  653. return False_;
  654. queue_posn_index = emalloc(q->size * sizeof(q->cursor));
  655. if(queue_posn_index == NULL) {
  656. efree(queue_index);
  657. return False_;
  658. }
  659. /* Walk queue putting pointers into array */
  660. d = Q_Head(q);
  661. for(i=0; i < q->size; i++) {
  662. queue_index[i] = d;
  663. queue_posn_index[i] = q->cursor;
  664. d = Q_Next(q);
  665. }
  666. /* Now sort the index */
  667. QuickSort(queue_index, 0, q->size - 1, Comp);
  668. /* Rearrange the actual queue into correct order */
  669. dn = q->head;
  670. i = 0;
  671. while(dn != NULL) {
  672. dn->data = queue_index[i++];
  673. dn = dn->next;
  674. }
  675. /* Re-position to original element */
  676. if(d != NULL)
  677. Q_Find(q, d, Comp);
  678. else Q_Head(q);
  679. q->sorted = True_;
  680. return True_;
  681. }
  682. /***
  683. *
  684. ** function : Q_BSearch
  685. *
  686. ** purpose : binary search of queue index for node containing key
  687. *
  688. ** parameters : queue pointer 'q', data pointer of key 'key',
  689. * Comp comparison function.
  690. *
  691. ** returns : integer index into array of node pointers,
  692. * or -1 if not found.
  693. *
  694. ** comments : see Q_Sort for description of 'Comp' function.
  695. *
  696. ***/
  697. static int Q_BSearch( queue *q, void *key,
  698. int (*Comp)(const void *, const void*))
  699. {
  700. int low, mid, hi, val;
  701. low = 0;
  702. hi = q->size - 1;
  703. while(low <= hi) {
  704. mid = (low + hi) / 2;
  705. val = Comp(key, queue_index[ mid ]);
  706. if(val < 0)
  707. hi = mid - 1;
  708. else if(val > 0)
  709. low = mid + 1;
  710. else /* Success */
  711. return mid;
  712. }
  713. /* Not Found */
  714. return -1;
  715. }
  716. /***
  717. *
  718. ** function : Q_Seek
  719. *
  720. ** purpose : use index to locate data according to key in 'data'
  721. *
  722. ** parameters : queue pointer 'q', data pointer 'data', Comp comparison
  723. * function.
  724. *
  725. ** returns : pointer to data or NULL if could not find it or could
  726. * not sort queue.
  727. *
  728. ** comments : see Q_Sort for description of 'Comp' function.
  729. *
  730. ***/
  731. void *Q_Seek(queue *q, void *data, int (*Comp)(const void *, const void *))
  732. {
  733. int idx;
  734. if (q == NULL) {
  735. return NULL;
  736. }
  737. if(!q->sorted) {
  738. if(!Q_Sort(q, Comp))
  739. return NULL;
  740. }
  741. idx = Q_BSearch(q, data, Comp);
  742. if(idx < 0)
  743. return NULL;
  744. q->cursor = queue_posn_index[idx];
  745. return queue_index[idx];
  746. }
  747. /***
  748. *
  749. ** function : Q_Insert
  750. *
  751. ** purpose : Insert an element into an indexed queue
  752. *
  753. ** parameters : queue pointer 'q', data pointer 'data', Comp comparison
  754. * function.
  755. *
  756. ** returns : pointer to data or NULL if could not find it or could
  757. * not sort queue.
  758. *
  759. ** comments : see Q_Sort for description of 'Comp' function.
  760. * WARNING! This code can be very slow since each new
  761. * element means a new Q_Sort. Should only be used for
  762. * the insertion of the odd element ,not the piecemeal
  763. * building of an entire queue.
  764. ***/
  765. int Q_Insert(queue *q, void *data, int (*Comp)(const void *, const void *))
  766. {
  767. if (q == NULL) {
  768. return False_;
  769. }
  770. Q_PushHead(q, data);
  771. if(!Q_Sort(q, Comp))
  772. return False_;
  773. return True_;
  774. }
  775. /* read only funcs for iterating through queue. above funcs modify queue */
  776. q_iter Q_Iter_Head(queue *q) {
  777. return q ? (q_iter)q->head : NULL;
  778. }
  779. q_iter Q_Iter_Tail(queue *q) {
  780. return q ? (q_iter)q->tail : NULL;
  781. }
  782. q_iter Q_Iter_Next(q_iter qi) {
  783. return qi ? (q_iter)((node*)qi)->next : NULL;
  784. }
  785. q_iter Q_Iter_Prev(q_iter qi) {
  786. return qi ? (q_iter)((node*)qi)->prev : NULL;
  787. }
  788. void * Q_Iter_Get(q_iter qi) {
  789. return qi ? ((node*)qi)->data : NULL;
  790. }
  791. int Q_Iter_Put(q_iter qi, void* data) {
  792. if(qi) {
  793. ((node*)qi)->data = data;
  794. return True_;
  795. }
  796. return False_;
  797. }