list.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. /*
  2. * list.c: lists handling implementation
  3. *
  4. * Copyright (C) 2000 Gary Pennington and Daniel Veillard.
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  11. * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  12. * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
  13. * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
  14. *
  15. * Author: Gary.Pennington@uk.sun.com
  16. */
  17. #define IN_LIBXML
  18. #include "libxml.h"
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <libxml/xmlmemory.h>
  22. #include <libxml/list.h>
  23. #include <libxml/globals.h>
  24. /*
  25. * Type definition are kept internal
  26. */
  27. struct _xmlLink
  28. {
  29. struct _xmlLink *next;
  30. struct _xmlLink *prev;
  31. void *data;
  32. };
  33. struct _xmlList
  34. {
  35. xmlLinkPtr sentinel;
  36. void (*linkDeallocator)(xmlLinkPtr );
  37. int (*linkCompare)(const void *, const void*);
  38. };
  39. /************************************************************************
  40. * *
  41. * Interfaces *
  42. * *
  43. ************************************************************************/
  44. /**
  45. * xmlLinkDeallocator:
  46. * @l: a list
  47. * @lk: a link
  48. *
  49. * Unlink and deallocate @lk from list @l
  50. */
  51. static void
  52. xmlLinkDeallocator(xmlListPtr l, xmlLinkPtr lk)
  53. {
  54. (lk->prev)->next = lk->next;
  55. (lk->next)->prev = lk->prev;
  56. if(l->linkDeallocator)
  57. l->linkDeallocator(lk);
  58. xmlFree(lk);
  59. }
  60. /**
  61. * xmlLinkCompare:
  62. * @data0: first data
  63. * @data1: second data
  64. *
  65. * Compares two arbitrary data
  66. *
  67. * Returns -1, 0 or 1 depending on whether data1 is greater equal or smaller
  68. * than data0
  69. */
  70. static int
  71. xmlLinkCompare(const void *data0, const void *data1)
  72. {
  73. if (data0 < data1)
  74. return (-1);
  75. else if (data0 == data1)
  76. return (0);
  77. return (1);
  78. }
  79. /**
  80. * xmlListLowerSearch:
  81. * @l: a list
  82. * @data: a data
  83. *
  84. * Search data in the ordered list walking from the beginning
  85. *
  86. * Returns the link containing the data or NULL
  87. */
  88. static xmlLinkPtr
  89. xmlListLowerSearch(xmlListPtr l, void *data)
  90. {
  91. xmlLinkPtr lk;
  92. if (l == NULL)
  93. return(NULL);
  94. for(lk = l->sentinel->next;lk != l->sentinel && l->linkCompare(lk->data, data) <0 ;lk = lk->next);
  95. return lk;
  96. }
  97. /**
  98. * xmlListHigherSearch:
  99. * @l: a list
  100. * @data: a data
  101. *
  102. * Search data in the ordered list walking backward from the end
  103. *
  104. * Returns the link containing the data or NULL
  105. */
  106. static xmlLinkPtr
  107. xmlListHigherSearch(xmlListPtr l, void *data)
  108. {
  109. xmlLinkPtr lk;
  110. if (l == NULL)
  111. return(NULL);
  112. for(lk = l->sentinel->prev;lk != l->sentinel && l->linkCompare(lk->data, data) >0 ;lk = lk->prev);
  113. return lk;
  114. }
  115. /**
  116. * xmlListSearch:
  117. * @l: a list
  118. * @data: a data
  119. *
  120. * Search data in the list
  121. *
  122. * Returns the link containing the data or NULL
  123. */
  124. static xmlLinkPtr
  125. xmlListLinkSearch(xmlListPtr l, void *data)
  126. {
  127. xmlLinkPtr lk;
  128. if (l == NULL)
  129. return(NULL);
  130. lk = xmlListLowerSearch(l, data);
  131. if (lk == l->sentinel)
  132. return NULL;
  133. else {
  134. if (l->linkCompare(lk->data, data) ==0)
  135. return lk;
  136. return NULL;
  137. }
  138. }
  139. /**
  140. * xmlListLinkReverseSearch:
  141. * @l: a list
  142. * @data: a data
  143. *
  144. * Search data in the list processing backward
  145. *
  146. * Returns the link containing the data or NULL
  147. */
  148. static xmlLinkPtr
  149. xmlListLinkReverseSearch(xmlListPtr l, void *data)
  150. {
  151. xmlLinkPtr lk;
  152. if (l == NULL)
  153. return(NULL);
  154. lk = xmlListHigherSearch(l, data);
  155. if (lk == l->sentinel)
  156. return NULL;
  157. else {
  158. if (l->linkCompare(lk->data, data) ==0)
  159. return lk;
  160. return NULL;
  161. }
  162. }
  163. /**
  164. * xmlListCreate:
  165. * @deallocator: an optional deallocator function
  166. * @compare: an optional comparison function
  167. *
  168. * Create a new list
  169. *
  170. * Returns the new list or NULL in case of error
  171. */
  172. xmlListPtr
  173. xmlListCreate(xmlListDeallocator deallocator, xmlListDataCompare compare)
  174. {
  175. xmlListPtr l;
  176. if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) {
  177. xmlGenericError(xmlGenericErrorContext,
  178. "Cannot initialize memory for list");
  179. return (NULL);
  180. }
  181. /* Initialize the list to NULL */
  182. memset(l, 0, sizeof(xmlList));
  183. /* Add the sentinel */
  184. if (NULL ==(l->sentinel = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
  185. xmlGenericError(xmlGenericErrorContext,
  186. "Cannot initialize memory for sentinel");
  187. xmlFree(l);
  188. return (NULL);
  189. }
  190. l->sentinel->next = l->sentinel;
  191. l->sentinel->prev = l->sentinel;
  192. l->sentinel->data = NULL;
  193. /* If there is a link deallocator, use it */
  194. if (deallocator != NULL)
  195. l->linkDeallocator = deallocator;
  196. /* If there is a link comparator, use it */
  197. if (compare != NULL)
  198. l->linkCompare = compare;
  199. else /* Use our own */
  200. l->linkCompare = xmlLinkCompare;
  201. return l;
  202. }
  203. /**
  204. * xmlListSearch:
  205. * @l: a list
  206. * @data: a search value
  207. *
  208. * Search the list for an existing value of @data
  209. *
  210. * Returns the value associated to @data or NULL in case of error
  211. */
  212. void *
  213. xmlListSearch(xmlListPtr l, void *data)
  214. {
  215. xmlLinkPtr lk;
  216. if (l == NULL)
  217. return(NULL);
  218. lk = xmlListLinkSearch(l, data);
  219. if (lk)
  220. return (lk->data);
  221. return NULL;
  222. }
  223. /**
  224. * xmlListReverseSearch:
  225. * @l: a list
  226. * @data: a search value
  227. *
  228. * Search the list in reverse order for an existing value of @data
  229. *
  230. * Returns the value associated to @data or NULL in case of error
  231. */
  232. void *
  233. xmlListReverseSearch(xmlListPtr l, void *data)
  234. {
  235. xmlLinkPtr lk;
  236. if (l == NULL)
  237. return(NULL);
  238. lk = xmlListLinkReverseSearch(l, data);
  239. if (lk)
  240. return (lk->data);
  241. return NULL;
  242. }
  243. /**
  244. * xmlListInsert:
  245. * @l: a list
  246. * @data: the data
  247. *
  248. * Insert data in the ordered list at the beginning for this value
  249. *
  250. * Returns 0 in case of success, 1 in case of failure
  251. */
  252. int
  253. xmlListInsert(xmlListPtr l, void *data)
  254. {
  255. xmlLinkPtr lkPlace, lkNew;
  256. if (l == NULL)
  257. return(1);
  258. lkPlace = xmlListLowerSearch(l, data);
  259. /* Add the new link */
  260. lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
  261. if (lkNew == NULL) {
  262. xmlGenericError(xmlGenericErrorContext,
  263. "Cannot initialize memory for new link");
  264. return (1);
  265. }
  266. lkNew->data = data;
  267. lkPlace = lkPlace->prev;
  268. lkNew->next = lkPlace->next;
  269. (lkPlace->next)->prev = lkNew;
  270. lkPlace->next = lkNew;
  271. lkNew->prev = lkPlace;
  272. return 0;
  273. }
  274. /**
  275. * xmlListAppend:
  276. * @l: a list
  277. * @data: the data
  278. *
  279. * Insert data in the ordered list at the end for this value
  280. *
  281. * Returns 0 in case of success, 1 in case of failure
  282. */
  283. int xmlListAppend(xmlListPtr l, void *data)
  284. {
  285. xmlLinkPtr lkPlace, lkNew;
  286. if (l == NULL)
  287. return(1);
  288. lkPlace = xmlListHigherSearch(l, data);
  289. /* Add the new link */
  290. lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
  291. if (lkNew == NULL) {
  292. xmlGenericError(xmlGenericErrorContext,
  293. "Cannot initialize memory for new link");
  294. return (1);
  295. }
  296. lkNew->data = data;
  297. lkNew->next = lkPlace->next;
  298. (lkPlace->next)->prev = lkNew;
  299. lkPlace->next = lkNew;
  300. lkNew->prev = lkPlace;
  301. return 0;
  302. }
  303. /**
  304. * xmlListDelete:
  305. * @l: a list
  306. *
  307. * Deletes the list and its associated data
  308. */
  309. void xmlListDelete(xmlListPtr l)
  310. {
  311. if (l == NULL)
  312. return;
  313. xmlListClear(l);
  314. xmlFree(l->sentinel);
  315. xmlFree(l);
  316. }
  317. /**
  318. * xmlListRemoveFirst:
  319. * @l: a list
  320. * @data: list data
  321. *
  322. * Remove the first instance associated to data in the list
  323. *
  324. * Returns 1 if a deallocation occured, or 0 if not found
  325. */
  326. int
  327. xmlListRemoveFirst(xmlListPtr l, void *data)
  328. {
  329. xmlLinkPtr lk;
  330. if (l == NULL)
  331. return(0);
  332. /*Find the first instance of this data */
  333. lk = xmlListLinkSearch(l, data);
  334. if (lk != NULL) {
  335. xmlLinkDeallocator(l, lk);
  336. return 1;
  337. }
  338. return 0;
  339. }
  340. /**
  341. * xmlListRemoveLast:
  342. * @l: a list
  343. * @data: list data
  344. *
  345. * Remove the last instance associated to data in the list
  346. *
  347. * Returns 1 if a deallocation occured, or 0 if not found
  348. */
  349. int
  350. xmlListRemoveLast(xmlListPtr l, void *data)
  351. {
  352. xmlLinkPtr lk;
  353. if (l == NULL)
  354. return(0);
  355. /*Find the last instance of this data */
  356. lk = xmlListLinkReverseSearch(l, data);
  357. if (lk != NULL) {
  358. xmlLinkDeallocator(l, lk);
  359. return 1;
  360. }
  361. return 0;
  362. }
  363. /**
  364. * xmlListRemoveAll:
  365. * @l: a list
  366. * @data: list data
  367. *
  368. * Remove the all instance associated to data in the list
  369. *
  370. * Returns the number of deallocation, or 0 if not found
  371. */
  372. int
  373. xmlListRemoveAll(xmlListPtr l, void *data)
  374. {
  375. int count=0;
  376. if (l == NULL)
  377. return(0);
  378. while(xmlListRemoveFirst(l, data))
  379. count++;
  380. return count;
  381. }
  382. /**
  383. * xmlListClear:
  384. * @l: a list
  385. *
  386. * Remove the all data in the list
  387. */
  388. void
  389. xmlListClear(xmlListPtr l)
  390. {
  391. xmlLinkPtr lk;
  392. if (l == NULL)
  393. return;
  394. lk = l->sentinel->next;
  395. while(lk != l->sentinel) {
  396. xmlLinkPtr next = lk->next;
  397. xmlLinkDeallocator(l, lk);
  398. lk = next;
  399. }
  400. }
  401. /**
  402. * xmlListEmpty:
  403. * @l: a list
  404. *
  405. * Is the list empty ?
  406. *
  407. * Returns 1 if the list is empty, 0 if not empty and -1 in case of error
  408. */
  409. int
  410. xmlListEmpty(xmlListPtr l)
  411. {
  412. if (l == NULL)
  413. return(-1);
  414. return (l->sentinel->next == l->sentinel);
  415. }
  416. /**
  417. * xmlListFront:
  418. * @l: a list
  419. *
  420. * Get the first element in the list
  421. *
  422. * Returns the first element in the list, or NULL
  423. */
  424. xmlLinkPtr
  425. xmlListFront(xmlListPtr l)
  426. {
  427. if (l == NULL)
  428. return(NULL);
  429. return (l->sentinel->next);
  430. }
  431. /**
  432. * xmlListEnd:
  433. * @l: a list
  434. *
  435. * Get the last element in the list
  436. *
  437. * Returns the last element in the list, or NULL
  438. */
  439. xmlLinkPtr
  440. xmlListEnd(xmlListPtr l)
  441. {
  442. if (l == NULL)
  443. return(NULL);
  444. return (l->sentinel->prev);
  445. }
  446. /**
  447. * xmlListSize:
  448. * @l: a list
  449. *
  450. * Get the number of elements in the list
  451. *
  452. * Returns the number of elements in the list or -1 in case of error
  453. */
  454. int
  455. xmlListSize(xmlListPtr l)
  456. {
  457. xmlLinkPtr lk;
  458. int count=0;
  459. if (l == NULL)
  460. return(-1);
  461. /* TODO: keep a counter in xmlList instead */
  462. for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next, count++);
  463. return count;
  464. }
  465. /**
  466. * xmlListPopFront:
  467. * @l: a list
  468. *
  469. * Removes the first element in the list
  470. */
  471. void
  472. xmlListPopFront(xmlListPtr l)
  473. {
  474. if(!xmlListEmpty(l))
  475. xmlLinkDeallocator(l, l->sentinel->next);
  476. }
  477. /**
  478. * xmlListPopBack:
  479. * @l: a list
  480. *
  481. * Removes the last element in the list
  482. */
  483. void
  484. xmlListPopBack(xmlListPtr l)
  485. {
  486. if(!xmlListEmpty(l))
  487. xmlLinkDeallocator(l, l->sentinel->prev);
  488. }
  489. /**
  490. * xmlListPushFront:
  491. * @l: a list
  492. * @data: new data
  493. *
  494. * add the new data at the beginning of the list
  495. *
  496. * Returns 1 if successful, 0 otherwise
  497. */
  498. int
  499. xmlListPushFront(xmlListPtr l, void *data)
  500. {
  501. xmlLinkPtr lkPlace, lkNew;
  502. if (l == NULL)
  503. return(0);
  504. lkPlace = l->sentinel;
  505. /* Add the new link */
  506. lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
  507. if (lkNew == NULL) {
  508. xmlGenericError(xmlGenericErrorContext,
  509. "Cannot initialize memory for new link");
  510. return (0);
  511. }
  512. lkNew->data = data;
  513. lkNew->next = lkPlace->next;
  514. (lkPlace->next)->prev = lkNew;
  515. lkPlace->next = lkNew;
  516. lkNew->prev = lkPlace;
  517. return 1;
  518. }
  519. /**
  520. * xmlListPushBack:
  521. * @l: a list
  522. * @data: new data
  523. *
  524. * add the new data at the end of the list
  525. *
  526. * Returns 1 if successful, 0 otherwise
  527. */
  528. int
  529. xmlListPushBack(xmlListPtr l, void *data)
  530. {
  531. xmlLinkPtr lkPlace, lkNew;
  532. if (l == NULL)
  533. return(0);
  534. lkPlace = l->sentinel->prev;
  535. /* Add the new link */
  536. if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
  537. xmlGenericError(xmlGenericErrorContext,
  538. "Cannot initialize memory for new link");
  539. return (0);
  540. }
  541. lkNew->data = data;
  542. lkNew->next = lkPlace->next;
  543. (lkPlace->next)->prev = lkNew;
  544. lkPlace->next = lkNew;
  545. lkNew->prev = lkPlace;
  546. return 1;
  547. }
  548. /**
  549. * xmlLinkGetData:
  550. * @lk: a link
  551. *
  552. * See Returns.
  553. *
  554. * Returns a pointer to the data referenced from this link
  555. */
  556. void *
  557. xmlLinkGetData(xmlLinkPtr lk)
  558. {
  559. if (lk == NULL)
  560. return(NULL);
  561. return lk->data;
  562. }
  563. /**
  564. * xmlListReverse:
  565. * @l: a list
  566. *
  567. * Reverse the order of the elements in the list
  568. */
  569. void
  570. xmlListReverse(xmlListPtr l)
  571. {
  572. xmlLinkPtr lk;
  573. xmlLinkPtr lkPrev;
  574. if (l == NULL)
  575. return;
  576. lkPrev = l->sentinel;
  577. for (lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) {
  578. lkPrev->next = lkPrev->prev;
  579. lkPrev->prev = lk;
  580. lkPrev = lk;
  581. }
  582. /* Fix up the last node */
  583. lkPrev->next = lkPrev->prev;
  584. lkPrev->prev = lk;
  585. }
  586. /**
  587. * xmlListSort:
  588. * @l: a list
  589. *
  590. * Sort all the elements in the list
  591. */
  592. void
  593. xmlListSort(xmlListPtr l)
  594. {
  595. xmlListPtr lTemp;
  596. if (l == NULL)
  597. return;
  598. if(xmlListEmpty(l))
  599. return;
  600. /* I think that the real answer is to implement quicksort, the
  601. * alternative is to implement some list copying procedure which
  602. * would be based on a list copy followed by a clear followed by
  603. * an insert. This is slow...
  604. */
  605. if (NULL ==(lTemp = xmlListDup(l)))
  606. return;
  607. xmlListClear(l);
  608. xmlListMerge(l, lTemp);
  609. xmlListDelete(lTemp);
  610. return;
  611. }
  612. /**
  613. * xmlListWalk:
  614. * @l: a list
  615. * @walker: a processing function
  616. * @user: a user parameter passed to the walker function
  617. *
  618. * Walk all the element of the first from first to last and
  619. * apply the walker function to it
  620. */
  621. void
  622. xmlListWalk(xmlListPtr l, xmlListWalker walker, const void *user) {
  623. xmlLinkPtr lk;
  624. if ((l == NULL) || (walker == NULL))
  625. return;
  626. for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) {
  627. if((walker(lk->data, user)) == 0)
  628. break;
  629. }
  630. }
  631. /**
  632. * xmlListReverseWalk:
  633. * @l: a list
  634. * @walker: a processing function
  635. * @user: a user parameter passed to the walker function
  636. *
  637. * Walk all the element of the list in reverse order and
  638. * apply the walker function to it
  639. */
  640. void
  641. xmlListReverseWalk(xmlListPtr l, xmlListWalker walker, const void *user) {
  642. xmlLinkPtr lk;
  643. if ((l == NULL) || (walker == NULL))
  644. return;
  645. for(lk = l->sentinel->prev; lk != l->sentinel; lk = lk->prev) {
  646. if((walker(lk->data, user)) == 0)
  647. break;
  648. }
  649. }
  650. /**
  651. * xmlListMerge:
  652. * @l1: the original list
  653. * @l2: the new list
  654. *
  655. * include all the elements of the second list in the first one and
  656. * clear the second list
  657. */
  658. void
  659. xmlListMerge(xmlListPtr l1, xmlListPtr l2)
  660. {
  661. xmlListCopy(l1, l2);
  662. xmlListClear(l2);
  663. }
  664. /**
  665. * xmlListDup:
  666. * @old: the list
  667. *
  668. * Duplicate the list
  669. *
  670. * Returns a new copy of the list or NULL in case of error
  671. */
  672. xmlListPtr
  673. xmlListDup(const xmlListPtr old)
  674. {
  675. xmlListPtr cur;
  676. if (old == NULL)
  677. return(NULL);
  678. /* Hmmm, how to best deal with allocation issues when copying
  679. * lists. If there is a de-allocator, should responsibility lie with
  680. * the new list or the old list. Surely not both. I'll arbitrarily
  681. * set it to be the old list for the time being whilst I work out
  682. * the answer
  683. */
  684. if (NULL ==(cur = xmlListCreate(NULL, old->linkCompare)))
  685. return (NULL);
  686. if (0 != xmlListCopy(cur, old))
  687. return NULL;
  688. return cur;
  689. }
  690. /**
  691. * xmlListCopy:
  692. * @cur: the new list
  693. * @old: the old list
  694. *
  695. * Move all the element from the old list in the new list
  696. *
  697. * Returns 0 in case of success 1 in case of error
  698. */
  699. int
  700. xmlListCopy(xmlListPtr cur, const xmlListPtr old)
  701. {
  702. /* Walk the old tree and insert the data into the new one */
  703. xmlLinkPtr lk;
  704. if ((old == NULL) || (cur == NULL))
  705. return(1);
  706. for(lk = old->sentinel->next; lk != old->sentinel; lk = lk->next) {
  707. if (0 !=xmlListInsert(cur, lk->data)) {
  708. xmlListDelete(cur);
  709. return (1);
  710. }
  711. }
  712. return (0);
  713. }
  714. /* xmlListUnique() */
  715. /* xmlListSwap */
  716. #define bottom_list
  717. #include "elfgcchack.h"