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 struct hash_do_baton
41 {
42   void *baton;
43   svn_iter_apr_hash_cb_t func;
44   svn_error_t *err;
45   apr_pool_t *iterpool;
46 };
47 
48 static
hash_do_callback(void * baton,const void * key,apr_ssize_t klen,const void * value)49 int hash_do_callback(void *baton,
50                      const void *key,
51                      apr_ssize_t klen,
52                      const void *value)
53 {
54   struct hash_do_baton *hdb = baton;
55 
56   svn_pool_clear(hdb->iterpool);
57   hdb->err = (*hdb->func)(hdb->baton, key, klen, (void *)value, hdb->iterpool);
58 
59   return hdb->err == SVN_NO_ERROR;
60 }
61 
62 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)63 svn_iter_apr_hash(svn_boolean_t *completed,
64                   apr_hash_t *hash,
65                   svn_iter_apr_hash_cb_t func,
66                   void *baton,
67                   apr_pool_t *pool)
68 {
69   struct hash_do_baton hdb;
70   svn_boolean_t error_received;
71 
72   hdb.func = func;
73   hdb.baton = baton;
74   hdb.iterpool = svn_pool_create(pool);
75 
76   error_received = !apr_hash_do(hash_do_callback, &hdb, hash);
77 
78   svn_pool_destroy(hdb.iterpool);
79 
80   if (completed)
81     *completed = !error_received;
82 
83   if (!error_received)
84     return SVN_NO_ERROR;
85 
86   if (hdb.err->apr_err == SVN_ERR_ITER_BREAK
87         && hdb.err != &internal_break_error)
88     {
89         /* Errors - except those created by svn_iter_break() -
90            need to be cleared when not further propagated. */
91         svn_error_clear(hdb.err);
92 
93         hdb.err = SVN_NO_ERROR;
94     }
95 
96   return hdb.err;
97 }
98 
99 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)100 svn_iter_apr_array(svn_boolean_t *completed,
101                    const apr_array_header_t *array,
102                    svn_iter_apr_array_cb_t func,
103                    void *baton,
104                    apr_pool_t *pool)
105 {
106   svn_error_t *err = SVN_NO_ERROR;
107   apr_pool_t *iterpool = svn_pool_create(pool);
108   int i;
109 
110   for (i = 0; (! err) && i < array->nelts; ++i)
111     {
112       void *item = array->elts + array->elt_size*i;
113 
114       svn_pool_clear(iterpool);
115 
116       err = (*func)(baton, item, iterpool);
117     }
118 
119   if (completed)
120     *completed = ! err;
121 
122   if (err && err->apr_err == SVN_ERR_ITER_BREAK)
123     {
124       if (err != &internal_break_error)
125         /* Errors - except those created by svn_iter_break() -
126            need to be cleared when not further propagated. */
127         svn_error_clear(err);
128 
129       err = SVN_NO_ERROR;
130     }
131 
132   /* Clear iterpool, because callers may clear the error but have no way
133      to clear the iterpool with potentially lots of allocated memory */
134   svn_pool_destroy(iterpool);
135 
136   return err;
137 }
138 
139 /* Note: Although this is a "__" function, it is in the public ABI, so
140  * we can never remove it or change its signature. */
141 svn_error_t *
svn_iter__break(void)142 svn_iter__break(void)
143 {
144   return &internal_break_error;
145 }
146 
147 #if !APR_VERSION_AT_LEAST(1, 5, 0)
apr_hash_this_key(apr_hash_index_t * hi)148 const void *apr_hash_this_key(apr_hash_index_t *hi)
149 {
150   const void *key;
151 
152   apr_hash_this((apr_hash_index_t *)hi, &key, NULL, NULL);
153   return key;
154 }
155 
apr_hash_this_key_len(apr_hash_index_t * hi)156 apr_ssize_t apr_hash_this_key_len(apr_hash_index_t *hi)
157 {
158   apr_ssize_t klen;
159 
160   apr_hash_this((apr_hash_index_t *)hi, NULL, &klen, NULL);
161   return klen;
162 }
163 
apr_hash_this_val(apr_hash_index_t * hi)164 void *apr_hash_this_val(apr_hash_index_t *hi)
165 {
166   void *val;
167 
168   apr_hash_this((apr_hash_index_t *)hi, NULL, NULL, &val);
169   return val;
170 }
171 #endif
172