source: src/router/proftpd/src/sets.c @ 12685

Last change on this file since 12685 was 12685, checked in by BrainSlayer, 4 years ago

new version

File size: 5.5 KB
Line 
1/*
2 * ProFTPD - FTP server daemon
3 * Copyright (c) 1997, 1998 Public Flood Software
4 * Copyright (c) 2001-2008 The ProFTPD Project team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
19 *
20 * As a special exemption, Public Flood Software/MacGyver aka Habeeb J. Dihu
21 * and other respective copyright holders give permission to link this program
22 * with OpenSSL, and distribute the resulting executable, without including
23 * the source code for OpenSSL in the source distribution.
24 */
25
26/*
27 * Generic set manipulation
28 * $Id: sets.c,v 1.15 2008/02/17 00:59:01 castaglia Exp $
29 */
30
31#include "conf.h"
32
33/* Create a new set, cmpfunc is a pointer to the function used to to compare
34 * members of the set ... it should return 1, 0, or -1 after the fashion of
35 * strcmp.  Returns NULL if memory allocation fails.
36 */
37
38xaset_t *xaset_create(pool *p, XASET_COMPARE cmpfunc) {
39  xaset_t *new_set;
40
41  if (p == NULL &&
42      permanent_pool == NULL) {
43    errno = EPERM;
44    return NULL;
45  }
46
47  p = p ? p : permanent_pool;
48
49  new_set = palloc(p, sizeof(xaset_t));
50
51  if (!new_set)
52    return NULL;
53
54  new_set->xas_list = NULL;
55  new_set->pool = p;
56  new_set->xas_compare = cmpfunc;
57
58  return new_set;
59}
60
61/* Inserts a new member into an existing set.  The member is inserted
62 * at the beginning of the set.  Returns 0 if successful, -1 otherwise (with
63 * errno set appropriately).
64 */
65int xaset_insert(xaset_t *set, xasetmember_t *member) {
66
67  if (set == NULL ||
68      member == NULL) {
69    errno = EINVAL;
70    return -1;
71  }
72
73  member->next = set->xas_list;
74
75  if (set->xas_list)
76    set->xas_list->prev = member;
77
78  set->xas_list = member;
79  return 0;
80}
81
82/* Inserts a new member into an existing set at the end of the list.
83 */
84int xaset_insert_end(xaset_t *set, xasetmember_t *member) {
85  xasetmember_t **tmp, *prev = NULL;
86
87  if (set == NULL ||
88      member == NULL) {
89    errno = EINVAL;
90    return -1;
91  }
92
93  for (tmp = &set->xas_list; *tmp; prev = *tmp, tmp = &(*tmp)->next)
94    ;
95
96  *tmp = member;
97  member->prev = prev;
98  member->next = NULL;
99
100  if (prev)
101    prev->next = member;
102
103  return 0;
104}
105
106/* Inserts a new member into an existing set, sorted using the set's compare
107 * callback.  If dups_allowed is non-0, returns 0 and the member is not added
108 * to the set.  Otherwise, it is added immediately before the first duplicate.
109 * If the set is not empty and not pre-sorted, results are undefined.
110 * Returns 0 if successful, -1 otherwise (with errno set appropriately).
111 */
112int xaset_insert_sort(xaset_t *set, xasetmember_t *member, int dups_allowed) {
113  xasetmember_t **setp = NULL, *mprev = NULL;
114
115  if (!set || !member || !set->xas_compare) {
116    errno = EINVAL;
117    return -1;
118  }
119
120  for (setp = &set->xas_list; *setp; setp = &(*setp)->next) {
121    int res;
122
123    res = set->xas_compare(member, *setp);
124    if (res <= 0) {
125      if (res == 0 &&
126          !dups_allowed)
127        return 0;
128      break;
129    }
130
131    mprev = *setp;
132  }
133
134  if (*setp)
135    (*setp)->prev = member;
136
137  member->prev = mprev;
138  member->next = *setp;
139  *setp = member;
140
141  return 0;
142}
143
144/* Remove a member from a set.  The set need not be sorted.  Note that this
145 * does NOT free the memory used by the member.  Returns 0 if successful,
146 * and -1 if there was a problem (with errno set appropriately).
147 */
148int xaset_remove(xaset_t *set, xasetmember_t *member) {
149  xasetmember_t *m = NULL;
150
151  if (set == NULL ||
152      member == NULL) {
153    errno = EINVAL;
154    return -1;
155  }
156
157  /* Check if member is actually a member of set. */
158  for (m = set->xas_list; m; m = m->next) {
159    if (m == member)
160      break;
161  }
162
163  if (m == NULL) {
164    errno = ENOENT;
165    return -1; 
166  }
167
168  if (member->prev)
169    member->prev->next = member->next;
170
171  else /* assume that member is first in the list */
172    set->xas_list = member->next;
173
174  if (member->next)
175    member->next->prev = member->prev;
176
177  member->next = member->prev = NULL;
178  return 0;
179}
180
181/* Perform an exact copy of the entire set, returning the new set.  msize
182 * specifies the size of each member.  If copyfunc is non-NULL, it is called
183 * instead to copy each member.  Returns NULL if out of memory condition
184 * occurs.
185 */
186xaset_t *xaset_copy(pool *p, xaset_t *set, size_t msize, XASET_MCOPY copyfunc) {
187  xaset_t *new_set;
188  xasetmember_t *n, *m, **pos;
189
190  if (set == NULL) {
191    errno = EINVAL;
192    return NULL;
193  }
194
195  if (!copyfunc && !msize) {
196    errno = EINVAL;
197    return NULL;
198  }
199
200  p = (p ? p : set->pool);
201
202  new_set = xaset_create(p, set->xas_compare);
203  if (new_set == NULL)
204    return NULL;
205
206  pos = &new_set->xas_list;
207
208  /* NOTE: xaset_insert_sort is not used here for performance reasons. */
209
210  for (m = set->xas_list; m; m = m->next) {
211    n = copyfunc ? copyfunc(m) : (xasetmember_t *) palloc(p, msize);
212    if (!n)
213      return NULL;                      /* Could clean up here */
214
215    if (!copyfunc)
216      memcpy(n, m, msize);
217
218    /* Create links */
219    n->prev = *pos;
220    n->next = NULL;
221    if (*pos)
222      pos = &(*pos)->next;
223    *pos = n;
224  }
225
226  return new_set;
227}
Note: See TracBrowser for help on using the repository browser.