home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / DCLAP 4j / network / nsclilib / ni_list.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-17  |  14.0 KB  |  474 lines  |  [TEXT/R*ch]

  1. /*      
  2. * ===========================================================================
  3. *
  4. *                            PUBLIC DOMAIN NOTICE                          
  5. *               National Center for Biotechnology Information
  6. *                                                                          
  7. *  This software/database is a "United States Government Work" under the   
  8. *  terms of the United States Copyright Act.  It was written as part of    
  9. *  the author's official duties as a United States Government employee and 
  10. *  thus cannot be copyrighted.  This software/database is freely available 
  11. *  to the public for use. The National Library of Medicine and the U.S.    
  12. *  Government have not placed any restriction on its use or reproduction.  
  13. *                                                                          
  14. *  Although all reasonable efforts have been taken to ensure the accuracy  
  15. *  and reliability of the software and data, the NLM and the U.S.          
  16. *  Government do not and cannot warrant the performance or results that    
  17. *  may be obtained by using this software or data. The NLM and the U.S.    
  18. *  Government disclaim all warranties, express or implied, including       
  19. *  warranties of performance, merchantability or fitness for any particular
  20. *  purpose.                                                                
  21. *                                                                          
  22. *  Please cite the author in any work or product based on this material.   
  23. *
  24. * ===========================================================================
  25. *
  26. * File Name:    ni_list.c
  27. *
  28. * Author:       Beatty, Gish
  29. *
  30. * Version Creation Date:        1/1/92
  31. *
  32. * $Revision: 1.1 $
  33. *
  34. * File Description: 
  35. *   List and ring management functions.
  36. *
  37. *
  38. * Modifications:  
  39. * --------------------------------------------------------------------------
  40. * Date     Name        Description of modification
  41. * -------  ----------  -----------------------------------------------------
  42. * 4/23/92  Epstein     Added extensive in-line commentary, and removed all tabs
  43. * 5/11/92  Epstein     Changed ListSwapAdj() to provide more rigorous testing
  44. *                      that its two arguments are adjacent in the list.
  45. * 5/14/92  Epstein     Added ListStrCopy() and ListStrDel()
  46. * 7/06/92  Epstein     Fixed bug in ListStrCopy(), where the newly created
  47. *                      list was not being returned to the caller ... whoops.
  48. *
  49. * ==========================================================================
  50. */
  51.  
  52. #include "ni_list.h"
  53.  
  54.  
  55.  
  56. /*
  57.  * Purpose:     Insert an item as the next element in a doubly linked list(ring)
  58.  *
  59.  * Parameters:
  60.  *   elem           Next element to be inserted; this is data only,not a NodePtr
  61.  *   ap             Insertion point
  62.  *
  63.  * Returns:
  64.  *                The newly allocated NodePtr, containing forward and backward
  65.  *                pointers and a pointer to elem
  66.  *
  67.  *
  68.  * Description:
  69.  *              Allocate the necessary memory for a "Node", attach the
  70.  *              caller's data to that Node, and insert the Node after the
  71.  *              specified node in the list, maintaining the integrity of
  72.  *              a doubly-linked ring. If there are no other items in the
  73.  *              ring, create a "minimal" ring which consists of the single
  74.  *              Node pointing to itself in both directions.
  75.  *
  76.  * Note:
  77.  *              Most "list" data is actually stored in a doubly-linked ring, as
  78.  *              shown below. Furthermore, note that each node only contains a
  79.  *              pointer to the actual data in the list, rather than the actual
  80.  *              data itself.
  81.  *
  82.  *          +------------------------------------------------------------------+
  83.  *          ^                                                                  |
  84.  *          |       +-------------------------------------------------------+  |
  85.  *          |       |                                                       ^  |
  86.  *          |       V                                                       |  |
  87.  *          |   +-------+       +-------+                       +-------+   |  |
  88.  *          |   | next  |------>| next  |------> ...    ------->| next  |-->+  |
  89.  *          |   +-------+       +-------+                       +-------+      |
  90.  *          +<--| last  |<------| last  |<------ ...    <-------| last  |<-----+
  91.  *              +-------+       +-------+                       +-------+
  92.  *              | elem  |       | elem  |                       | elem  |
  93.  *              +-------+       +-------+                       +-------+
  94.  *                  |               |                               |
  95.  *                  |               |                               |
  96.  *                  V               V                               V
  97.  *              +-------+       +-------+                       +-------+
  98.  *              | actual|       | actual|                       | actual|
  99.  *              | data  |       | data  |                       | data  |
  100.  *              +-------+       +-------+                       +-------+
  101.  */
  102.  
  103. NodePtr 
  104. ListInsert(VoidPtr elem, NodePtr ap)                     /* ptr to node to insert after */
  105. {
  106.     NodePtr             np;
  107.     
  108.     if (elem == NULL)
  109.         return NULL;
  110.     
  111.     np = (NodePtr) MemNew(sizeof(Node));
  112.     np->elem = elem;
  113.     
  114.     if (ap == NULL) {           /* no nodes in list */
  115.         np->last = np;
  116.         np->next = np;
  117.         return np;
  118.     }
  119.     else {                              /* 1 or more nodes in list */
  120.         np->next = ap->next;
  121.         ap->next = np;
  122.         np->next->last = np;
  123.         np->last = ap;
  124.         return np;
  125.     }
  126. } /* ListInsert */
  127.  
  128.  
  129.  
  130. /*
  131.  * Purpose:     Insert an item as the previous element in a doubly linked
  132.  *              list(ring)
  133.  *
  134.  * Parameters:
  135.  *   elem           Next element to be inserted; this is data only,not a NodePtr
  136.  *   ap             Insertion point
  137.  *
  138.  * Returns:
  139.  *                The newly allocated NodePtr, containing forward and backward
  140.  *                pointers and a pointer to elem
  141.  *
  142.  *
  143.  * Description:
  144.  *              Insert the specified item into the ring, before the specified
  145.  *              insertion point. In the case where the specified insertion
  146.  *              point was NULL, this is equivalent to ListInsert().
  147.  */
  148.  
  149. NodePtr 
  150. ListInsertPrev(VoidPtr elem, NodePtr ap)                     /* ptr to node to insert before */
  151. {
  152.     NodePtr             np;
  153.     
  154.     np = ap;
  155.     if (ap != NULL)
  156.         ap = ap->last;          /* previous node */
  157.     
  158.     ap = ListInsert(elem, ap);
  159.     return (np == NULL) ? ap : np;
  160. } /* ListInsertPrev */
  161.  
  162.  
  163.  
  164. /*
  165.  * Purpose:     Delete a single node from a list or ring
  166.  *
  167.  * Parameters:
  168.  *   np             Node to be deleted
  169.  *
  170.  * Returns:
  171.  *                A pointer to the "next" node in the list/ring, after the
  172.  *                deleted node.
  173.  *
  174.  *
  175.  * Description:
  176.  *              Delete the specified node from a list or ring. It is the
  177.  *              responsibility of the caller to free the memory associated
  178.  *              with the "elem" (data), if appropriate.
  179.  */
  180.  
  181. NodePtr 
  182. ListDelete(NodePtr np)
  183. {
  184.     NodePtr             nextnode, lastnode;
  185.     
  186.     if (np == NULL)
  187.         return NULL;
  188.     
  189.     nextnode = np->next;
  190.     lastnode = np->last;
  191.     
  192.     if (nextnode == NULL && lastnode == NULL)   /* only node in a list */
  193.         ;
  194.     else if (nextnode == NULL) {                /* last in a list */
  195.         np->last->next = NULL;
  196.         nextnode = np->last;
  197.     }
  198.     else if (lastnode == NULL) {                /* first in a list */
  199.         np->next->last = NULL;
  200.         nextnode = np->next;
  201.     }
  202.     else if (np == nextnode)                    /* last in a ring */
  203.         nextnode = NULL;
  204.     else {                                      /* node with both neighbors */
  205.         np->last->next = nextnode;
  206.         np->next->last = np->last;
  207.     }
  208.     
  209.     MemFree(np);                        /* assumes element memory has been freed */
  210.     return nextnode;
  211. } /* ListDelete */
  212.  
  213.  
  214.  
  215. /*
  216.  * Purpose:     Get the next element from a list or ring (non-destructively)
  217.  *
  218.  * Parameters:
  219.  *   np             Node before the node to be selected
  220.  *
  221.  * Returns:
  222.  *                A pointer to the "next" node in the list/ring (or NULL
  223.  *                if the list/ring was NULL). Note that for a list, the
  224.  *                returned value can also be NULL.
  225.  *
  226.  *
  227.  * Description:
  228.  *              Return the "next" node in the list or rin.g
  229.  */
  230.  
  231. NodePtr 
  232. ListGetNext(NodePtr np)
  233. {
  234.     if (np == NULL)
  235.         return NULL;
  236.     return np->next;
  237. } /* ListGetNext */
  238.  
  239.  
  240.  
  241. /*
  242.  * Purpose:     Swap two adjacent nodes in a list or ring
  243.  *
  244.  * Parameters:
  245.  *   np1            "Prior" node
  246.  *   np2            "Next" node
  247.  *
  248.  *
  249.  * Description:
  250.  *              Swap the two specified elements, provided that they are
  251.  *              adjacent, and np1 precedes np2.
  252.  */
  253.  
  254. void 
  255. ListSwapAdj(NodePtr np1, NodePtr np2)       /* priornode, nextnode */
  256. {
  257.     if (np1 == NULL || np2 == NULL || np1->next->last != np1) /* must be sane */
  258.         return;
  259.  
  260.     if (np1->next != np2 || np2->last != np1)             /* must be in order */
  261.         return;
  262.     
  263.     if (np1->last != NULL)
  264.         np1->last->next = np2;
  265.     
  266.     if (np2->next != NULL)
  267.         np2->next->last = np1;
  268.     
  269.     np1->next = np2->next;
  270.     np2->last = np1->last;
  271.     
  272.     np1->last = np2;
  273.     np2->next = np1;
  274. } /* ListSwapAdj */
  275.  
  276.  
  277.  
  278. /*
  279.  * Purpose:     Sort the specified ring/list
  280.  *
  281.  * Parameters:
  282.  *   head           Head of the list to be sorted
  283.  *   cmpfunc        Comparison function (return values are like memcmp())
  284.  *   order          ASCEND or DESCEND
  285.  *
  286.  * Returns:
  287.  *              A pointer to the first element of the sorted ring or list
  288.  *
  289.  *
  290.  * Description:
  291.  *              Sort the specified list, in place, using bubble sort, and
  292.  *              the specified comparison function. Determine prior to sorting
  293.  *              whether this is a list or a ring. If it's a ring, break the
  294.  *              ring prior to sorting, and restore it to a ring topology
  295.  *              after sorting has been completed.
  296.  */
  297.  
  298. NodePtr 
  299. ListSort(NodePtr head, int (*cmpfunc )PROTO ((NodePtr, NodePtr )), int order)                                  /* 0 if equal, LT 0 if 1st element > 2nd element */
  300. {
  301.     NodePtr             np;
  302.     Boolean             sorted = FALSE, ring;
  303.     int         result;
  304.     
  305.     if (head == NULL)
  306.         return NULL;
  307.     if (head->last == NULL)
  308.         ring = FALSE;
  309.     else
  310.         ring = TRUE;
  311.     if (ring)
  312.         ListBreakRing(head);
  313.     
  314.     /* just bubble sort for now */
  315.     
  316.     while (! sorted) {
  317.         np = head;
  318.         sorted = TRUE;
  319.         
  320.         while (np->next != NULL) {
  321.             result = (*cmpfunc)(np, np->next);
  322.             if ((result > 0 && order == ASCEND) || (result < 0 && order == DESCEND)) {
  323.                 sorted = FALSE;
  324.                 if (np == head)
  325.                     head = np->next;    /* keep head pointing at 1st element */
  326.                 ListSwapAdj(np, np->next);
  327.             }
  328.             else
  329.                 np = np->next;
  330.         }
  331.     }
  332.     
  333.     if (ring)
  334.         ListConnectRing(head);
  335.     return head;        /* ptr to first element */
  336. } /* ListSort */
  337.  
  338.  
  339.  
  340. /*
  341.  * Purpose:     Break the specified ring into a non-circular (linear) list
  342.  *
  343.  * Parameters:
  344.  *   np             Head of the ring to be broken
  345.  *
  346.  *
  347.  * Description:
  348.  *              Break the specified ring between its head and tail.
  349.  *
  350.  * Note:
  351.  *              This function may be called safely (without effect) if the
  352.  *              passed parameter is already a list, rather than a ring.
  353.  */
  354.  
  355. void 
  356. ListBreakRing(NodePtr np)
  357. {
  358.     if (np == NULL)
  359.         return;
  360.     if (np->last == NULL)
  361.         return;
  362.     
  363.     np->last->next = NULL;
  364.     np->last = NULL;
  365. } /* ListBreakRing */
  366.  
  367.  
  368.  
  369. /*
  370.  * Purpose:     Convert a list into a ring.
  371.  *
  372.  * Parameters:
  373.  *   head           Head of the list to be connected
  374.  *
  375.  *
  376.  * Description:
  377.  *              Connect the specified list between its head and tail, producing
  378.  *              a ring.
  379.  *
  380.  * Note:
  381.  *              This function may be called safely (without effect) if the
  382.  *              passed parameter is already a ring, rather than a list.
  383.  */
  384.  
  385. void 
  386. ListConnectRing(NodePtr head)
  387. {
  388.     NodePtr     np;
  389.     
  390.     if (head == NULL)
  391.         return;
  392.     
  393.     np = head;
  394.     
  395.     while (np->next != NULL) {
  396.         np = np->next;
  397.         if (np == head)
  398.             return;
  399.     }
  400.     
  401.     np->next = head;
  402.     head->last = np;
  403. } /* ListConnectRing */
  404.  
  405.  
  406. /*
  407.  * Purpose:     Copy a list where the list elements are character strings
  408.  *
  409.  * Parameters:
  410.  *   strlist        List to be copied
  411.  *
  412.  * Returns:
  413.  *              A copy of the original list (which may be NULL)
  414.  *
  415.  *
  416.  * Description:
  417.  *              Create a list which is a copy of the original list, and
  418.  *              also make copies of the strings.
  419.  *
  420.  * Note:
  421.  *              There is no obvious way to make a generic list copying
  422.  *              routine, because, in general, the length of each list
  423.  *              element is unknown. This is a simple case where it is
  424.  *              easy to copy a list.
  425.  */
  426.  
  427. NodePtr
  428. ListStrCopy (NodePtr strlist)
  429. {
  430.     NodePtr newlist = NULL;
  431.     NodePtr np = strlist;
  432.     CharPtr stringtext;
  433.  
  434.     if (strlist == NULL)
  435.         return NULL;
  436.  
  437.     do {
  438.         stringtext = StringSave((CharPtr) np->elem);
  439.         newlist = ListInsert(stringtext, newlist);
  440.         np = ListGetNext(np);
  441.     } while (np != NULL && np != strlist);
  442.  
  443.     return newlist->next; /* points to 1st element in new list */
  444. }
  445.  
  446.  
  447. /*
  448.  * Purpose:     Delete a list where the list elements are character strings
  449.  *
  450.  * Parameters:
  451.  *   np             List to be deleted
  452.  *
  453.  *
  454.  * Description:
  455.  *              Delete the list nodes and the character string data associated
  456.  *              with each node.
  457.  *
  458.  * Note:
  459.  *              This routine will work for any list element which is a single
  460.  *              block of memory. However, it will not work in the more general
  461.  *              case where a list element in turn references other memory
  462.  *              which must also be freed.
  463.  */
  464.  
  465. void
  466. ListStrDel (NodePtr np)
  467. {
  468.     while (np != NULL)
  469.     {
  470.         MemFree (np->elem);
  471.         np = ListDelete(np);
  472.     }
  473. }
  474.