sets.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:8k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /*
  2.  * ProFTPD - FTP server daemon
  3.  * Copyright (c) 1997, 1998 Public Flood Software
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  18.  */
  19. /*
  20.  * Generic set manipulation
  21.  *
  22.  * TODO: Use a hash table to greatly speed up set manipulation on
  23.  *       large sets.
  24.  *
  25.  * HISTORY:
  26.  *
  27.  * 3/31/97: Flood-
  28.  *   Changed all memory allocation routines to be "pool" compliant
  29.  *   -- now requires "pool{.c,.h}".
  30.  */
  31. #include "conf.h"
  32. #define POOL(x) ((x) ? (x) : permanent_pool)
  33. /* Create a new set, compf is a pointer to the function used
  34.    to to compare members of the set ... it should return 1, 0, or
  35.    -1 after the fashion of strcmp.  Returns NULL if memory allocation
  36.    fails.
  37. */
  38. xaset_t *xaset_create(pool *pool, XASET_COMPARE compf)
  39. {
  40.   xaset_t *newset = palloc(POOL(pool),sizeof(xaset_t));
  41.   if(!newset) return NULL;
  42.   newset->xas_list = NULL;
  43.   newset->mempool = POOL(pool);
  44.   newset->xas_compare = compf;
  45.   return newset;
  46. }
  47. /* Inserts a new member into an existing set.  The member is inserted
  48.    at the beginning of the set.
  49.    Returns: 1 if successful
  50.             0 if one or more arguments is invalid or something
  51.               is wrong with the set
  52.            -1 error (not used)
  53. */
  54. int xaset_insert(xaset_t *set, xasetmember_t *member)
  55. {
  56.   if(!set || !member)
  57.     return 0;
  58.   member->next = set->xas_list;
  59.   if(set->xas_list)
  60.     set->xas_list->prev = member;
  61.   set->xas_list = member;
  62.   return 1;
  63. }
  64. /* Inserts a new member into an existing set at the end
  65.  * of the list.
  66.  */
  67. int xaset_insert_end(xaset_t *set, xasetmember_t *member)
  68. {
  69.   xasetmember_t **tmp,*prev = NULL;
  70.   if(!set || !member)
  71.     return 0;
  72.   for(tmp = &set->xas_list; *tmp; prev=*tmp, tmp=&(*tmp)->next) ;
  73.   *tmp = member;
  74.   member->prev = prev;
  75.   member->next = NULL;
  76.   return 1;
  77. }
  78. /* Inserts a new member into an existing set, sorted using the set's
  79.    compare callback.  If dupes_allowed is non-0, returns 0 and the
  80.    member is not added to the set.  Otherwise, it is added immediately
  81.    before the first dupelicate.  If the set is not empty and not pre-
  82.    sorted, results are undefined.
  83.    Returns: 1 if successful
  84.             0 if bad arguments or duplicate member
  85.            -1 error (not used, applicable error would be in errno)
  86. */
  87. int xaset_insert_sort(xaset_t *set, xasetmember_t *member, int dupes_allowed)
  88. {
  89.   xasetmember_t **setp,*mprev = NULL;
  90.   int c;
  91.   if(!set || !member || !set->xas_compare)
  92.     return 0;
  93.   for(setp = &set->xas_list; *setp; setp=&(*setp)->next) {
  94.     if((c = set->xas_compare(member,*setp)) <= 0) {
  95.       if(c == 0 && !dupes_allowed)
  96.         return 0;
  97.       break;
  98.     }
  99.     mprev = *setp;
  100.   }
  101.   if(*setp)
  102.     (*setp)->prev = member;
  103.   member->prev = mprev;
  104.   member->next = *setp;
  105.   *setp = member;
  106.   return 1;
  107. }
  108. /* Remove a member from a set.  The set need not be sorted.  Note that
  109.    this does NOT free the memory used by the member.  No check is performed
  110.    to validate that `member' is truely a member of `set'.
  111.    Returns: 1 if successful
  112.             0 if invalid args
  113.            -1 error (check errno, unused at this time)
  114. */
  115. int xaset_remove(xaset_t *set, xasetmember_t *member)
  116. {
  117.   if(!set || !member)
  118.     return 0;
  119.   if(member->prev)
  120.     member->prev->next = member->next;
  121.   else /* assume that member is first in the list */ 
  122.     set->xas_list = member->next;
  123.   if(member->next)
  124.     member->next->prev = member->prev;
  125.   member->next = member->prev = NULL;
  126.   return 1;
  127. }
  128. /* Perform a set union.  The two sets do not need to be sorted, however
  129.    the returned new set will be.  Duplicate entries are, as per
  130.    normal set logic, removed.  Return value is the new set, or
  131.    NULL if out-of-memory or one or more arguments is invalid.
  132. */
  133. xaset_t *xaset_union(pool *pool,xaset_t *set1, xaset_t *set2,
  134.                      size_t msize, XASET_MCOPY copyf)
  135. {
  136.   xaset_t *newset;
  137.   xasetmember_t *setp,*n;
  138.   xaset_t *setv[3];
  139.   xaset_t **setcp;
  140.   setv[0] = set1; setv[1] = set2; setv[2] = NULL;
  141.   if(!set1 || !set2 || (!msize && !copyf))
  142.     return NULL;
  143.   pool = (pool ? pool : (set1->mempool ? set1->mempool : set2->mempool));
  144.   if(!(newset = xaset_create(pool,set1->xas_compare)))
  145.     return NULL;
  146.   
  147.   for(setcp = setv; *setcp; setcp++)
  148.     for(setp = (*setcp)->xas_list; setp; setp=setp->next) {
  149.       n = copyf ? copyf(setp) : (xasetmember_t*)palloc(pool,msize);
  150.       if(!n)
  151.         return NULL; /* Could cleanup here */
  152.       if(!copyf)
  153.         memcpy(n,setp,msize);
  154.       if(xaset_insert_sort(newset,n,0) == -1)
  155.         return NULL;
  156.     }
  157.   return newset;
  158. }
  159. /* Perform set subtraction: set1 - set2, creating a new set composed of
  160.    all the elements in set1 that are not in set2.  NULL is returned if
  161.    a new set cannot be created (out-of-memory), or either set1 or set2
  162.    are NULL.  If the copyf argument is non-NULL it is used to copy each
  163.    applicable element to the new set.  If either of the two sets is
  164.    unsorted, the result will be undefined.  set1's comparison callback
  165.    function is used when comparing members of each set.
  166. */
  167. xaset_t *xaset_subtract(pool *pool,xaset_t *set1, xaset_t *set2,
  168.                         size_t msize, XASET_MCOPY copyf)
  169. {
  170.   xaset_t *newset;
  171.   xasetmember_t *set1p,*set2p,*n,**pos;
  172.   int c;
  173.   if(!set1 || !set2 || (!msize && !copyf))
  174.     return NULL;
  175.   pool = (pool ? pool : (set1->mempool ? set1->mempool : set2->mempool));
  176.   if(!(newset = xaset_create(pool,set1->xas_compare)))
  177.     return NULL;
  178.   pos = &newset->xas_list;
  179.   /* NOTE: xaset_insert_sort is not used here for performance
  180.      reasons. */
  181.   for(set1p = set1->xas_list, set2p = set2->xas_list; set1p; 
  182.       set1p = set1p->next) {
  183.     if(!set2p || (c = set1->xas_compare(set1p,set2p)) < 0) {
  184.       /* Copy if set2 is exhausted or set1p's "value" is less than
  185.          set2p's. */
  186.       n = copyf ? copyf(set1p) : (xasetmember_t*)palloc(pool,msize);
  187.       if(!n)
  188.         return NULL; /* Could cleanup here */
  189.       if(!copyf)
  190.         memcpy(n,set1p,msize);
  191.       /* Create links */
  192.       n->prev = *pos;
  193.       n->next = NULL;
  194.       if(*pos)
  195.         pos = &(*pos)->next;
  196.       *pos = n;
  197.     } else if(c >= 0) {
  198.       /* Traverse set2 until we reach a point where set2 is
  199.          exhausted or set2p is "greater" than set1p */
  200.       while((set2p = set2p->next) != NULL && 
  201.             set1->xas_compare(set1p,set2p) > 0) ;
  202.       /* In case there are dupes in set1, examine the next (if any)
  203.          value(s) and skip if necessary */
  204.       while(set1p->next && set1->xas_compare(set1p,set1p->next) == 0) 
  205.         set1p = set1p->next;
  206.     }
  207.   }
  208.   return newset;
  209. }
  210. /* Perform an exact copy of the entire set, returning the new set.
  211.    msize specifies the size of each member.  If copyf is non-NULL, it
  212.    is called instead to copy each member.
  213.    Returns NULL if out of memory condition occurs
  214. */
  215. xaset_t *xaset_copy(pool *pool, xaset_t *set, size_t msize, XASET_MCOPY copyf)
  216. {
  217.   xaset_t *newset;
  218.   xasetmember_t *n,*p,**pos;
  219.   if(!copyf && !msize)
  220.     return NULL;
  221.   pool = (pool ? pool : set->mempool);
  222.   if(!(newset = xaset_create(pool,set->xas_compare)))
  223.     return NULL;
  224.   pos = &newset->xas_list;
  225.   /* NOTE: xaset_insert_sort is not used here for performance
  226.      reasons. */
  227.   for(p = set->xas_list; p; p=p->next) {
  228.     n = copyf ? copyf(p) : (xasetmember_t*)palloc(pool,msize);
  229.     if(!n)
  230.       return NULL; /* Could clean up here */
  231.     if(!copyf)
  232.       memcpy(n,p,msize);
  233.     /* Create links */
  234.     n->prev = *pos;
  235.     n->next = NULL;
  236.     if(*pos)
  237.       pos = &(*pos)->next;
  238.     *pos = n;
  239.   }
  240.   return newset;
  241. }