PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/cpluff/kazlib/list.c

https://bitbucket.org/bgiorgini/xbmc
C | 935 lines | 577 code | 179 blank | 179 comment | 120 complexity | 8a856037b7f7a94dae642fcd45ef2c0a MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-3.0, BSD-3-Clause, GPL-2.0, LGPL-3.0, 0BSD, LGPL-2.0, AGPL-1.0, LGPL-2.1
  1. /*
  2. * List Abstract Data Type
  3. * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
  4. *
  5. * Free Software License:
  6. *
  7. * All rights are reserved by the author, with the following exceptions:
  8. * Permission is granted to freely reproduce and distribute this software,
  9. * possibly in exchange for a fee, provided that this copyright notice appears
  10. * intact. Permission is also granted to adapt this software to produce
  11. * derivative works, as long as the modified versions carry this copyright
  12. * notice and additional notices stating that the work has been modified.
  13. * This source code may be translated into executable form and incorporated
  14. * into proprietary software; there is no requirement for such software to
  15. * contain a copyright notice related to this source.
  16. *
  17. * $Id: list.c,v 1.19.2.1 2000/04/17 01:07:21 kaz Exp $
  18. * $Name: kazlib_1_20 $
  19. */
  20. /*
  21. * Modified by Johannes Lehtinen in 2006-2007.
  22. * Included the definition of CP_HIDDEN macro and used it in declarations and
  23. * definitions to hide Kazlib symbols when building a shared C-Pluff library.
  24. */
  25. #include <stdlib.h>
  26. #include <stddef.h>
  27. #include <assert.h>
  28. #define LIST_IMPLEMENTATION
  29. #include "list.h"
  30. #define next list_next
  31. #define prev list_prev
  32. #define data list_data
  33. #define pool list_pool
  34. #define fre list_free
  35. #define size list_size
  36. #define nilnode list_nilnode
  37. #define nodecount list_nodecount
  38. #define maxcount list_maxcount
  39. #define list_nil(L) (&(L)->nilnode)
  40. #define list_first_priv(L) ((L)->nilnode.next)
  41. #define list_last_priv(L) ((L)->nilnode.prev)
  42. #define lnode_next(N) ((N)->next)
  43. #define lnode_prev(N) ((N)->prev)
  44. #ifdef KAZLIB_RCSID
  45. static const char rcsid[] = "$Id: list.c,v 1.19.2.1 2000/04/17 01:07:21 kaz Exp $";
  46. #endif
  47. /*
  48. * Initialize a list object supplied by the client such that it becomes a valid
  49. * empty list. If the list is to be ``unbounded'', the maxcount should be
  50. * specified as LISTCOUNT_T_MAX, or, alternately, as -1. The value zero
  51. * is not permitted.
  52. */
  53. CP_HIDDEN list_t *list_init(list_t *list, listcount_t maxcount)
  54. {
  55. assert (maxcount != 0);
  56. list->nilnode.next = &list->nilnode;
  57. list->nilnode.prev = &list->nilnode;
  58. list->nodecount = 0;
  59. list->maxcount = maxcount;
  60. return list;
  61. }
  62. /*
  63. * Dynamically allocate a list object using malloc(), and initialize it so that
  64. * it is a valid empty list. If the list is to be ``unbounded'', the maxcount
  65. * should be specified as LISTCOUNT_T_MAX, or, alternately, as -1.
  66. */
  67. CP_HIDDEN list_t *list_create(listcount_t maxcount)
  68. {
  69. list_t *new = malloc(sizeof *new);
  70. if (new) {
  71. assert (maxcount != 0);
  72. new->nilnode.next = &new->nilnode;
  73. new->nilnode.prev = &new->nilnode;
  74. new->nodecount = 0;
  75. new->maxcount = maxcount;
  76. }
  77. return new;
  78. }
  79. /*
  80. * Destroy a dynamically allocated list object.
  81. * The client must remove the nodes first.
  82. */
  83. CP_HIDDEN void list_destroy(list_t *list)
  84. {
  85. assert (list_isempty(list));
  86. free(list);
  87. }
  88. /*
  89. * Free all of the nodes of a list. The list must contain only
  90. * dynamically allocated nodes. After this call, the list
  91. * is empty.
  92. */
  93. CP_HIDDEN void list_destroy_nodes(list_t *list)
  94. {
  95. lnode_t *lnode = list_first_priv(list), *nil = list_nil(list), *tmp;
  96. while (lnode != nil) {
  97. tmp = lnode->next;
  98. lnode->next = NULL;
  99. lnode->prev = NULL;
  100. lnode_destroy(lnode);
  101. lnode = tmp;
  102. }
  103. list_init(list, list->maxcount);
  104. }
  105. /*
  106. * Return all of the nodes of a list to a node pool. The nodes in
  107. * the list must all have come from the same pool.
  108. */
  109. CP_HIDDEN void list_return_nodes(list_t *list, lnodepool_t *pool)
  110. {
  111. lnode_t *lnode = list_first_priv(list), *tmp, *nil = list_nil(list);
  112. while (lnode != nil) {
  113. tmp = lnode->next;
  114. lnode->next = NULL;
  115. lnode->prev = NULL;
  116. lnode_return(pool, lnode);
  117. lnode = tmp;
  118. }
  119. list_init(list, list->maxcount);
  120. }
  121. /*
  122. * Insert the node ``new'' into the list immediately after ``this'' node.
  123. */
  124. CP_HIDDEN void list_ins_after(list_t *list, lnode_t *new, lnode_t *this)
  125. {
  126. lnode_t *that = this->next;
  127. assert (new != NULL);
  128. assert (!list_contains(list, new));
  129. assert (!lnode_is_in_a_list(new));
  130. assert (this == list_nil(list) || list_contains(list, this));
  131. assert (list->nodecount + 1 > list->nodecount);
  132. new->prev = this;
  133. new->next = that;
  134. that->prev = new;
  135. this->next = new;
  136. list->nodecount++;
  137. assert (list->nodecount <= list->maxcount);
  138. }
  139. /*
  140. * Insert the node ``new'' into the list immediately before ``this'' node.
  141. */
  142. CP_HIDDEN void list_ins_before(list_t *list, lnode_t *new, lnode_t *this)
  143. {
  144. lnode_t *that = this->prev;
  145. assert (new != NULL);
  146. assert (!list_contains(list, new));
  147. assert (!lnode_is_in_a_list(new));
  148. assert (this == list_nil(list) || list_contains(list, this));
  149. assert (list->nodecount + 1 > list->nodecount);
  150. new->next = this;
  151. new->prev = that;
  152. that->next = new;
  153. this->prev = new;
  154. list->nodecount++;
  155. assert (list->nodecount <= list->maxcount);
  156. }
  157. /*
  158. * Delete the given node from the list.
  159. */
  160. CP_HIDDEN lnode_t *list_delete(list_t *list, lnode_t *del)
  161. {
  162. lnode_t *next = del->next;
  163. lnode_t *prev = del->prev;
  164. assert (list_contains(list, del));
  165. prev->next = next;
  166. next->prev = prev;
  167. list->nodecount--;
  168. del->next = del->prev = NULL;
  169. return del;
  170. }
  171. /*
  172. * For each node in the list, execute the given function. The list,
  173. * current node and the given context pointer are passed on each
  174. * call to the function.
  175. */
  176. CP_HIDDEN void list_process(list_t *list, void *context,
  177. void (* function)(list_t *list, lnode_t *lnode, void *context))
  178. {
  179. lnode_t *node = list_first_priv(list), *next, *nil = list_nil(list);
  180. while (node != nil) {
  181. /* check for callback function deleting */
  182. /* the next node from under us */
  183. assert (list_contains(list, node));
  184. next = node->next;
  185. function(list, node, context);
  186. node = next;
  187. }
  188. }
  189. /*
  190. * Dynamically allocate a list node and assign it the given piece of data.
  191. */
  192. CP_HIDDEN lnode_t *lnode_create(void *data)
  193. {
  194. lnode_t *new = malloc(sizeof *new);
  195. if (new) {
  196. new->data = data;
  197. new->next = NULL;
  198. new->prev = NULL;
  199. }
  200. return new;
  201. }
  202. /*
  203. * Initialize a user-supplied lnode.
  204. */
  205. CP_HIDDEN lnode_t *lnode_init(lnode_t *lnode, void *data)
  206. {
  207. lnode->data = data;
  208. lnode->next = NULL;
  209. lnode->prev = NULL;
  210. return lnode;
  211. }
  212. /*
  213. * Destroy a dynamically allocated node.
  214. */
  215. CP_HIDDEN void lnode_destroy(lnode_t *lnode)
  216. {
  217. assert (!lnode_is_in_a_list(lnode));
  218. free(lnode);
  219. }
  220. /*
  221. * Initialize a node pool object to use a user-supplied set of nodes.
  222. * The ``nodes'' pointer refers to an array of lnode_t objects, containing
  223. * ``n'' elements.
  224. */
  225. CP_HIDDEN lnodepool_t *lnode_pool_init(lnodepool_t *pool, lnode_t *nodes, listcount_t n)
  226. {
  227. listcount_t i;
  228. assert (n != 0);
  229. pool->pool = nodes;
  230. pool->fre = nodes;
  231. pool->size = n;
  232. for (i = 0; i < n - 1; i++) {
  233. nodes[i].next = nodes + i + 1;
  234. }
  235. nodes[i].next = NULL;
  236. nodes[i].prev = nodes; /* to make sure node is marked ``on list'' */
  237. return pool;
  238. }
  239. /*
  240. * Create a dynamically allocated pool of n nodes.
  241. */
  242. CP_HIDDEN lnodepool_t *lnode_pool_create(listcount_t n)
  243. {
  244. lnodepool_t *pool;
  245. lnode_t *nodes;
  246. assert (n != 0);
  247. pool = malloc(sizeof *pool);
  248. if (!pool)
  249. return NULL;
  250. nodes = malloc(n * sizeof *nodes);
  251. if (!nodes) {
  252. free(pool);
  253. return NULL;
  254. }
  255. lnode_pool_init(pool, nodes, n);
  256. return pool;
  257. }
  258. /*
  259. * Determine whether the given pool is from this pool.
  260. */
  261. CP_HIDDEN int lnode_pool_isfrom(lnodepool_t *pool, lnode_t *node)
  262. {
  263. listcount_t i;
  264. /* this is carefully coded this way because ANSI C forbids pointers
  265. to different objects from being subtracted or compared other
  266. than for exact equality */
  267. for (i = 0; i < pool->size; i++) {
  268. if (pool->pool + i == node)
  269. return 1;
  270. }
  271. return 0;
  272. }
  273. /*
  274. * Destroy a dynamically allocated pool of nodes.
  275. */
  276. CP_HIDDEN void lnode_pool_destroy(lnodepool_t *p)
  277. {
  278. free(p->pool);
  279. free(p);
  280. }
  281. /*
  282. * Borrow a node from a node pool. Returns a null pointer if the pool
  283. * is exhausted.
  284. */
  285. CP_HIDDEN lnode_t *lnode_borrow(lnodepool_t *pool, void *data)
  286. {
  287. lnode_t *new = pool->fre;
  288. if (new) {
  289. pool->fre = new->next;
  290. new->data = data;
  291. new->next = NULL;
  292. new->prev = NULL;
  293. }
  294. return new;
  295. }
  296. /*
  297. * Return a node to a node pool. A node must be returned to the pool
  298. * from which it came.
  299. */
  300. CP_HIDDEN void lnode_return(lnodepool_t *pool, lnode_t *node)
  301. {
  302. assert (lnode_pool_isfrom(pool, node));
  303. assert (!lnode_is_in_a_list(node));
  304. node->next = pool->fre;
  305. node->prev = node;
  306. pool->fre = node;
  307. }
  308. /*
  309. * Determine whether the given list contains the given node.
  310. * According to this function, a list does not contain its nilnode.
  311. */
  312. CP_HIDDEN int list_contains(list_t *list, lnode_t *node)
  313. {
  314. lnode_t *n, *nil = list_nil(list);
  315. for (n = list_first_priv(list); n != nil; n = lnode_next(n)) {
  316. if (node == n)
  317. return 1;
  318. }
  319. return 0;
  320. }
  321. /*
  322. * A more generalized variant of list_transfer. This one removes a
  323. * ``slice'' from the source list and appends it to the destination
  324. * list.
  325. */
  326. CP_HIDDEN void list_extract(list_t *dest, list_t *source, lnode_t *first, lnode_t *last)
  327. {
  328. listcount_t moved = 1;
  329. assert (first == NULL || list_contains(source, first));
  330. assert (last == NULL || list_contains(source, last));
  331. if (first == NULL || last == NULL)
  332. return;
  333. /* adjust the destination list so that the slice is spliced out */
  334. first->prev->next = last->next;
  335. last->next->prev = first->prev;
  336. /* graft the splice at the end of the dest list */
  337. last->next = &dest->nilnode;
  338. first->prev = dest->nilnode.prev;
  339. dest->nilnode.prev->next = first;
  340. dest->nilnode.prev = last;
  341. while (first != last) {
  342. first = first->next;
  343. assert (first != list_nil(source)); /* oops, last before first! */
  344. moved++;
  345. }
  346. /* assert no overflows */
  347. assert (source->nodecount - moved <= source->nodecount);
  348. assert (dest->nodecount + moved >= dest->nodecount);
  349. /* assert no weirdness */
  350. assert (moved <= source->nodecount);
  351. source->nodecount -= moved;
  352. dest->nodecount += moved;
  353. /* assert list sanity */
  354. assert (list_verify(source));
  355. assert (list_verify(dest));
  356. }
  357. /*
  358. * Split off a trailing sequence of nodes from the source list and relocate
  359. * them to the tail of the destination list. The trailing sequence begins
  360. * with node ``first'' and terminates with the last node of the source
  361. * list. The nodes are added to the end of the new list in their original
  362. * order.
  363. */
  364. CP_HIDDEN void list_transfer(list_t *dest, list_t *source, lnode_t *first)
  365. {
  366. listcount_t moved = 1;
  367. lnode_t *last;
  368. assert (first == NULL || list_contains(source, first));
  369. if (first == NULL)
  370. return;
  371. last = source->nilnode.prev;
  372. source->nilnode.prev = first->prev;
  373. first->prev->next = &source->nilnode;
  374. last->next = &dest->nilnode;
  375. first->prev = dest->nilnode.prev;
  376. dest->nilnode.prev->next = first;
  377. dest->nilnode.prev = last;
  378. while (first != last) {
  379. first = first->next;
  380. moved++;
  381. }
  382. /* assert no overflows */
  383. assert (source->nodecount - moved <= source->nodecount);
  384. assert (dest->nodecount + moved >= dest->nodecount);
  385. /* assert no weirdness */
  386. assert (moved <= source->nodecount);
  387. source->nodecount -= moved;
  388. dest->nodecount += moved;
  389. /* assert list sanity */
  390. assert (list_verify(source));
  391. assert (list_verify(dest));
  392. }
  393. CP_HIDDEN void list_merge(list_t *dest, list_t *sour,
  394. int compare (const void *, const void *))
  395. {
  396. lnode_t *dn, *sn, *tn;
  397. lnode_t *d_nil = list_nil(dest), *s_nil = list_nil(sour);
  398. /* Nothing to do if source and destination list are the same. */
  399. if (dest == sour)
  400. return;
  401. /* overflow check */
  402. assert (list_count(sour) + list_count(dest) >= list_count(sour));
  403. /* lists must be sorted */
  404. assert (list_is_sorted(sour, compare));
  405. assert (list_is_sorted(dest, compare));
  406. dn = list_first_priv(dest);
  407. sn = list_first_priv(sour);
  408. while (dn != d_nil && sn != s_nil) {
  409. if (compare(lnode_get(dn), lnode_get(sn)) >= 0) {
  410. tn = lnode_next(sn);
  411. list_delete(sour, sn);
  412. list_ins_before(dest, sn, dn);
  413. sn = tn;
  414. } else {
  415. dn = lnode_next(dn);
  416. }
  417. }
  418. if (dn != d_nil)
  419. return;
  420. if (sn != s_nil)
  421. list_transfer(dest, sour, sn);
  422. }
  423. CP_HIDDEN void list_sort(list_t *list, int compare(const void *, const void *))
  424. {
  425. list_t extra;
  426. listcount_t middle;
  427. lnode_t *node;
  428. if (list_count(list) > 1) {
  429. middle = list_count(list) / 2;
  430. node = list_first_priv(list);
  431. list_init(&extra, list_count(list) - middle);
  432. while (middle--)
  433. node = lnode_next(node);
  434. list_transfer(&extra, list, node);
  435. list_sort(list, compare);
  436. list_sort(&extra, compare);
  437. list_merge(list, &extra, compare);
  438. }
  439. assert (list_is_sorted(list, compare));
  440. }
  441. CP_HIDDEN lnode_t *list_find(list_t *list, const void *key, int compare(const void *, const void *))
  442. {
  443. lnode_t *node;
  444. for (node = list_first_priv(list); node != list_nil(list); node = node->next) {
  445. if (compare(lnode_get(node), key) == 0)
  446. return node;
  447. }
  448. return 0;
  449. }
  450. /*
  451. * Return 1 if the list is in sorted order, 0 otherwise
  452. */
  453. CP_HIDDEN int list_is_sorted(list_t *list, int compare(const void *, const void *))
  454. {
  455. lnode_t *node, *next, *nil;
  456. next = nil = list_nil(list);
  457. node = list_first_priv(list);
  458. if (node != nil)
  459. next = lnode_next(node);
  460. for (; next != nil; node = next, next = lnode_next(next)) {
  461. if (compare(lnode_get(node), lnode_get(next)) > 0)
  462. return 0;
  463. }
  464. return 1;
  465. }
  466. /*
  467. * Get rid of macro functions definitions so they don't interfere
  468. * with the actual definitions
  469. */
  470. #undef list_isempty
  471. #undef list_isfull
  472. #undef lnode_pool_isempty
  473. #undef list_append
  474. #undef list_prepend
  475. #undef list_first
  476. #undef list_last
  477. #undef list_next
  478. #undef list_prev
  479. #undef list_count
  480. #undef list_del_first
  481. #undef list_del_last
  482. #undef lnode_put
  483. #undef lnode_get
  484. /*
  485. * Return 1 if the list is empty, 0 otherwise
  486. */
  487. CP_HIDDEN int list_isempty(list_t *list)
  488. {
  489. return list->nodecount == 0;
  490. }
  491. /*
  492. * Return 1 if the list is full, 0 otherwise
  493. * Permitted only on bounded lists.
  494. */
  495. CP_HIDDEN int list_isfull(list_t *list)
  496. {
  497. return list->nodecount == list->maxcount;
  498. }
  499. /*
  500. * Check if the node pool is empty.
  501. */
  502. CP_HIDDEN int lnode_pool_isempty(lnodepool_t *pool)
  503. {
  504. return (pool->fre == NULL);
  505. }
  506. /*
  507. * Add the given node at the end of the list
  508. */
  509. CP_HIDDEN void list_append(list_t *list, lnode_t *node)
  510. {
  511. list_ins_before(list, node, &list->nilnode);
  512. }
  513. /*
  514. * Add the given node at the beginning of the list.
  515. */
  516. CP_HIDDEN void list_prepend(list_t *list, lnode_t *node)
  517. {
  518. list_ins_after(list, node, &list->nilnode);
  519. }
  520. /*
  521. * Retrieve the first node of the list
  522. */
  523. CP_HIDDEN lnode_t *list_first(list_t *list)
  524. {
  525. if (list->nilnode.next == &list->nilnode)
  526. return NULL;
  527. return list->nilnode.next;
  528. }
  529. /*
  530. * Retrieve the last node of the list
  531. */
  532. CP_HIDDEN lnode_t *list_last(list_t *list)
  533. {
  534. if (list->nilnode.prev == &list->nilnode)
  535. return NULL;
  536. return list->nilnode.prev;
  537. }
  538. /*
  539. * Retrieve the count of nodes in the list
  540. */
  541. CP_HIDDEN listcount_t list_count(list_t *list)
  542. {
  543. return list->nodecount;
  544. }
  545. /*
  546. * Remove the first node from the list and return it.
  547. */
  548. CP_HIDDEN lnode_t *list_del_first(list_t *list)
  549. {
  550. return list_delete(list, list->nilnode.next);
  551. }
  552. /*
  553. * Remove the last node from the list and return it.
  554. */
  555. CP_HIDDEN lnode_t *list_del_last(list_t *list)
  556. {
  557. return list_delete(list, list->nilnode.prev);
  558. }
  559. /*
  560. * Associate a data item with the given node.
  561. */
  562. CP_HIDDEN void lnode_put(lnode_t *lnode, void *data)
  563. {
  564. lnode->data = data;
  565. }
  566. /*
  567. * Retrieve the data item associated with the node.
  568. */
  569. CP_HIDDEN void *lnode_get(lnode_t *lnode)
  570. {
  571. return lnode->data;
  572. }
  573. /*
  574. * Retrieve the node's successor. If there is no successor,
  575. * NULL is returned.
  576. */
  577. CP_HIDDEN lnode_t *list_next(list_t *list, lnode_t *lnode)
  578. {
  579. assert (list_contains(list, lnode));
  580. if (lnode->next == list_nil(list))
  581. return NULL;
  582. return lnode->next;
  583. }
  584. /*
  585. * Retrieve the node's predecessor. See comment for lnode_next().
  586. */
  587. CP_HIDDEN lnode_t *list_prev(list_t *list, lnode_t *lnode)
  588. {
  589. assert (list_contains(list, lnode));
  590. if (lnode->prev == list_nil(list))
  591. return NULL;
  592. return lnode->prev;
  593. }
  594. /*
  595. * Return 1 if the lnode is in some list, otherwise return 0.
  596. */
  597. CP_HIDDEN int lnode_is_in_a_list(lnode_t *lnode)
  598. {
  599. return (lnode->next != NULL || lnode->prev != NULL);
  600. }
  601. CP_HIDDEN int list_verify(list_t *list)
  602. {
  603. lnode_t *node = list_first_priv(list), *nil = list_nil(list);
  604. listcount_t count = list_count(list);
  605. if (node->prev != nil)
  606. return 0;
  607. if (count > list->maxcount)
  608. return 0;
  609. while (node != nil && count--) {
  610. if (node->next->prev != node)
  611. return 0;
  612. node = node->next;
  613. }
  614. if (count != 0 || node != nil)
  615. return 0;
  616. return 1;
  617. }
  618. #ifdef KAZLIB_TEST_MAIN
  619. #include <stdio.h>
  620. #include <string.h>
  621. #include <ctype.h>
  622. #include <stdarg.h>
  623. typedef char input_t[256];
  624. static int tokenize(char *string, ...)
  625. {
  626. char **tokptr;
  627. va_list arglist;
  628. int tokcount = 0;
  629. va_start(arglist, string);
  630. tokptr = va_arg(arglist, char **);
  631. while (tokptr) {
  632. while (*string && isspace((unsigned char) *string))
  633. string++;
  634. if (!*string)
  635. break;
  636. *tokptr = string;
  637. while (*string && !isspace((unsigned char) *string))
  638. string++;
  639. tokptr = va_arg(arglist, char **);
  640. tokcount++;
  641. if (!*string)
  642. break;
  643. *string++ = 0;
  644. }
  645. va_end(arglist);
  646. return tokcount;
  647. }
  648. static int comparef(const void *key1, const void *key2)
  649. {
  650. return strcmp(key1, key2);
  651. }
  652. static char *dupstring(char *str)
  653. {
  654. int sz = strlen(str) + 1;
  655. char *new = malloc(sz);
  656. if (new)
  657. memcpy(new, str, sz);
  658. return new;
  659. }
  660. int main(void)
  661. {
  662. input_t in;
  663. list_t *l = list_create(LISTCOUNT_T_MAX);
  664. lnode_t *ln;
  665. char *tok1, *val;
  666. int prompt = 0;
  667. char *help =
  668. "a <val> append value to list\n"
  669. "d <val> delete value from list\n"
  670. "l <val> lookup value in list\n"
  671. "s sort list\n"
  672. "c show number of entries\n"
  673. "t dump whole list\n"
  674. "p turn prompt on\n"
  675. "q quit";
  676. if (!l)
  677. puts("list_create failed");
  678. for (;;) {
  679. if (prompt)
  680. putchar('>');
  681. fflush(stdout);
  682. if (!fgets(in, sizeof(input_t), stdin))
  683. break;
  684. switch(in[0]) {
  685. case '?':
  686. puts(help);
  687. break;
  688. case 'a':
  689. if (tokenize(in+1, &tok1, (char **) 0) != 1) {
  690. puts("what?");
  691. break;
  692. }
  693. val = dupstring(tok1);
  694. ln = lnode_create(val);
  695. if (!val || !ln) {
  696. puts("allocation failure");
  697. if (ln)
  698. lnode_destroy(ln);
  699. free(val);
  700. break;
  701. }
  702. list_append(l, ln);
  703. break;
  704. case 'd':
  705. if (tokenize(in+1, &tok1, (char **) 0) != 1) {
  706. puts("what?");
  707. break;
  708. }
  709. ln = list_find(l, tok1, comparef);
  710. if (!ln) {
  711. puts("list_find failed");
  712. break;
  713. }
  714. list_delete(l, ln);
  715. val = lnode_get(ln);
  716. lnode_destroy(ln);
  717. free(val);
  718. break;
  719. case 'l':
  720. if (tokenize(in+1, &tok1, (char **) 0) != 1) {
  721. puts("what?");
  722. break;
  723. }
  724. ln = list_find(l, tok1, comparef);
  725. if (!ln)
  726. puts("list_find failed");
  727. else
  728. puts("found");
  729. break;
  730. case 's':
  731. list_sort(l, comparef);
  732. break;
  733. case 'c':
  734. printf("%lu\n", (unsigned long) list_count(l));
  735. break;
  736. case 't':
  737. for (ln = list_first(l); ln != 0; ln = list_next(l, ln))
  738. puts(lnode_get(ln));
  739. break;
  740. case 'q':
  741. exit(0);
  742. break;
  743. case '\0':
  744. break;
  745. case 'p':
  746. prompt = 1;
  747. break;
  748. default:
  749. putchar('?');
  750. putchar('\n');
  751. break;
  752. }
  753. }
  754. return 0;
  755. }
  756. #endif /* defined TEST_MAIN */