PageRenderTime 62ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/c/src/list.c

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