iter.c revision 289180
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
30static 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)
41struct 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
49static
50int 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
64svn_error_t *
65svn_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
139svn_error_t *
140svn_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. */
181svn_error_t *
182svn_iter__break(void)
183{
184  return &internal_break_error;
185}
186
187#if !APR_VERSION_AT_LEAST(1, 5, 0)
188const void *apr_hash_this_key(apr_hash_index_t *hi)
189{
190  const void *key;
191
192  apr_hash_this((apr_hash_index_t *)hi, &key, NULL, NULL);
193  return key;
194}
195
196apr_ssize_t apr_hash_this_key_len(apr_hash_index_t *hi)
197{
198  apr_ssize_t klen;
199
200  apr_hash_this((apr_hash_index_t *)hi, NULL, &klen, NULL);
201  return klen;
202}
203
204void *apr_hash_this_val(apr_hash_index_t *hi)
205{
206  void *val;
207
208  apr_hash_this((apr_hash_index_t *)hi, NULL, NULL, &val);
209  return val;
210}
211#endif
212