1 /* iter.c : iteration drivers
2 *
3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 * ====================================================================
21 */
22
23
24 #include "svn_iter.h"
25 #include "svn_pools.h"
26 #include "private/svn_dep_compat.h"
27
28 #include "svn_error_codes.h"
29
30 static svn_error_t internal_break_error =
31 {
32 SVN_ERR_ITER_BREAK, /* APR status */
33 NULL, /* message */
34 NULL, /* child error */
35 NULL, /* pool */
36 __FILE__, /* file name */
37 __LINE__ /* line number */
38 };
39
40 #if APR_VERSION_AT_LEAST(1, 4, 0)
41 struct hash_do_baton
42 {
43 void *baton;
44 svn_iter_apr_hash_cb_t func;
45 svn_error_t *err;
46 apr_pool_t *iterpool;
47 };
48
49 static
hash_do_callback(void * baton,const void * key,apr_ssize_t klen,const void * value)50 int hash_do_callback(void *baton,
51 const void *key,
52 apr_ssize_t klen,
53 const void *value)
54 {
55 struct hash_do_baton *hdb = baton;
56
57 svn_pool_clear(hdb->iterpool);
58 hdb->err = (*hdb->func)(hdb->baton, key, klen, (void *)value, hdb->iterpool);
59
60 return hdb->err == SVN_NO_ERROR;
61 }
62 #endif
63
64 svn_error_t *
svn_iter_apr_hash(svn_boolean_t * completed,apr_hash_t * hash,svn_iter_apr_hash_cb_t func,void * baton,apr_pool_t * pool)65 svn_iter_apr_hash(svn_boolean_t *completed,
66 apr_hash_t *hash,
67 svn_iter_apr_hash_cb_t func,
68 void *baton,
69 apr_pool_t *pool)
70 {
71 #if APR_VERSION_AT_LEAST(1, 4, 0)
72 struct hash_do_baton hdb;
73 svn_boolean_t error_received;
74
75 hdb.func = func;
76 hdb.baton = baton;
77 hdb.iterpool = svn_pool_create(pool);
78
79 error_received = !apr_hash_do(hash_do_callback, &hdb, hash);
80
81 svn_pool_destroy(hdb.iterpool);
82
83 if (completed)
84 *completed = !error_received;
85
86 if (!error_received)
87 return SVN_NO_ERROR;
88
89 if (hdb.err->apr_err == SVN_ERR_ITER_BREAK
90 && hdb.err != &internal_break_error)
91 {
92 /* Errors - except those created by svn_iter_break() -
93 need to be cleared when not further propagated. */
94 svn_error_clear(hdb.err);
95
96 hdb.err = SVN_NO_ERROR;
97 }
98
99 return hdb.err;
100 #else
101 svn_error_t *err = SVN_NO_ERROR;
102 apr_pool_t *iterpool = svn_pool_create(pool);
103 apr_hash_index_t *hi;
104
105 for (hi = apr_hash_first(pool, hash);
106 ! err && hi; hi = apr_hash_next(hi))
107 {
108 const void *key;
109 void *val;
110 apr_ssize_t len;
111
112 svn_pool_clear(iterpool);
113
114 apr_hash_this(hi, &key, &len, &val);
115 err = (*func)(baton, key, len, val, iterpool);
116 }
117
118 if (completed)
119 *completed = ! err;
120
121 if (err && err->apr_err == SVN_ERR_ITER_BREAK)
122 {
123 if (err != &internal_break_error)
124 /* Errors - except those created by svn_iter_break() -
125 need to be cleared when not further propagated. */
126 svn_error_clear(err);
127
128 err = SVN_NO_ERROR;
129 }
130
131 /* Clear iterpool, because callers may clear the error but have no way
132 to clear the iterpool with potentially lots of allocated memory */
133 svn_pool_destroy(iterpool);
134
135 return err;
136 #endif
137 }
138
139 svn_error_t *
svn_iter_apr_array(svn_boolean_t * completed,const apr_array_header_t * array,svn_iter_apr_array_cb_t func,void * baton,apr_pool_t * pool)140 svn_iter_apr_array(svn_boolean_t *completed,
141 const apr_array_header_t *array,
142 svn_iter_apr_array_cb_t func,
143 void *baton,
144 apr_pool_t *pool)
145 {
146 svn_error_t *err = SVN_NO_ERROR;
147 apr_pool_t *iterpool = svn_pool_create(pool);
148 int i;
149
150 for (i = 0; (! err) && i < array->nelts; ++i)
151 {
152 void *item = array->elts + array->elt_size*i;
153
154 svn_pool_clear(iterpool);
155
156 err = (*func)(baton, item, iterpool);
157 }
158
159 if (completed)
160 *completed = ! err;
161
162 if (err && err->apr_err == SVN_ERR_ITER_BREAK)
163 {
164 if (err != &internal_break_error)
165 /* Errors - except those created by svn_iter_break() -
166 need to be cleared when not further propagated. */
167 svn_error_clear(err);
168
169 err = SVN_NO_ERROR;
170 }
171
172 /* Clear iterpool, because callers may clear the error but have no way
173 to clear the iterpool with potentially lots of allocated memory */
174 svn_pool_destroy(iterpool);
175
176 return err;
177 }
178
179 /* Note: Although this is a "__" function, it is in the public ABI, so
180 * we can never remove it or change its signature. */
181 svn_error_t *
svn_iter__break(void)182 svn_iter__break(void)
183 {
184 return &internal_break_error;
185 }
186
187 /* Note about the type casts: apr_hash_this() does not expect a const hash
188 * index pointer even though it does not modify the hash index. In
189 * Subversion we're trying to be const-correct, so these functions all take
190 * a const hash index and we cast away the const when passing it down to
191 * APR. (A compiler may warn about casting away 'const', but at least this
192 * cast is explicit and gathered in one place.) */
193
svn__apr_hash_index_key(const apr_hash_index_t * hi)194 const void *svn__apr_hash_index_key(const apr_hash_index_t *hi)
195 {
196 const void *key;
197
198 apr_hash_this((apr_hash_index_t *)hi, &key, NULL, NULL);
199 return key;
200 }
201
svn__apr_hash_index_klen(const apr_hash_index_t * hi)202 apr_ssize_t svn__apr_hash_index_klen(const apr_hash_index_t *hi)
203 {
204 apr_ssize_t klen;
205
206 apr_hash_this((apr_hash_index_t *)hi, NULL, &klen, NULL);
207 return klen;
208 }
209
svn__apr_hash_index_val(const apr_hash_index_t * hi)210 void *svn__apr_hash_index_val(const apr_hash_index_t *hi)
211 {
212 void *val;
213
214 apr_hash_this((apr_hash_index_t *)hi, NULL, NULL, &val);
215 return val;
216 }
217