diff options
Diffstat (limited to 'subversion/libsvn_subr/iter.c')
-rw-r--r-- | subversion/libsvn_subr/iter.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/subversion/libsvn_subr/iter.c b/subversion/libsvn_subr/iter.c new file mode 100644 index 0000000..45ec489 --- /dev/null +++ b/subversion/libsvn_subr/iter.c @@ -0,0 +1,216 @@ +/* iter.c : iteration drivers + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + + +#include "svn_iter.h" +#include "svn_pools.h" +#include "private/svn_dep_compat.h" + +#include "svn_error_codes.h" + +static svn_error_t internal_break_error = + { + SVN_ERR_ITER_BREAK, /* APR status */ + NULL, /* message */ + NULL, /* child error */ + NULL, /* pool */ + __FILE__, /* file name */ + __LINE__ /* line number */ + }; + +#if APR_VERSION_AT_LEAST(1, 4, 0) +struct hash_do_baton +{ + void *baton; + svn_iter_apr_hash_cb_t func; + svn_error_t *err; + apr_pool_t *iterpool; +}; + +static +int hash_do_callback(void *baton, + const void *key, + apr_ssize_t klen, + const void *value) +{ + struct hash_do_baton *hdb = baton; + + svn_pool_clear(hdb->iterpool); + hdb->err = (*hdb->func)(hdb->baton, key, klen, (void *)value, hdb->iterpool); + + return hdb->err == SVN_NO_ERROR; +} +#endif + +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) +{ +#if APR_VERSION_AT_LEAST(1, 4, 0) + struct hash_do_baton hdb; + svn_boolean_t error_received; + + hdb.func = func; + hdb.baton = baton; + hdb.iterpool = svn_pool_create(pool); + + error_received = !apr_hash_do(hash_do_callback, &hdb, hash); + + svn_pool_destroy(hdb.iterpool); + + if (completed) + *completed = !error_received; + + if (!error_received) + return SVN_NO_ERROR; + + if (hdb.err->apr_err == SVN_ERR_ITER_BREAK + && hdb.err != &internal_break_error) + { + /* Errors - except those created by svn_iter_break() - + need to be cleared when not further propagated. */ + svn_error_clear(hdb.err); + + hdb.err = SVN_NO_ERROR; + } + + return hdb.err; +#else + svn_error_t *err = SVN_NO_ERROR; + apr_pool_t *iterpool = svn_pool_create(pool); + apr_hash_index_t *hi; + + for (hi = apr_hash_first(pool, hash); + ! err && hi; hi = apr_hash_next(hi)) + { + const void *key; + void *val; + apr_ssize_t len; + + svn_pool_clear(iterpool); + + apr_hash_this(hi, &key, &len, &val); + err = (*func)(baton, key, len, val, iterpool); + } + + if (completed) + *completed = ! err; + + if (err && err->apr_err == SVN_ERR_ITER_BREAK) + { + if (err != &internal_break_error) + /* Errors - except those created by svn_iter_break() - + need to be cleared when not further propagated. */ + svn_error_clear(err); + + err = SVN_NO_ERROR; + } + + /* Clear iterpool, because callers may clear the error but have no way + to clear the iterpool with potentially lots of allocated memory */ + svn_pool_destroy(iterpool); + + return err; +#endif +} + +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) +{ + svn_error_t *err = SVN_NO_ERROR; + apr_pool_t *iterpool = svn_pool_create(pool); + int i; + + for (i = 0; (! err) && i < array->nelts; ++i) + { + void *item = array->elts + array->elt_size*i; + + svn_pool_clear(iterpool); + + err = (*func)(baton, item, iterpool); + } + + if (completed) + *completed = ! err; + + if (err && err->apr_err == SVN_ERR_ITER_BREAK) + { + if (err != &internal_break_error) + /* Errors - except those created by svn_iter_break() - + need to be cleared when not further propagated. */ + svn_error_clear(err); + + err = SVN_NO_ERROR; + } + + /* Clear iterpool, because callers may clear the error but have no way + to clear the iterpool with potentially lots of allocated memory */ + svn_pool_destroy(iterpool); + + return err; +} + +/* Note: Although this is a "__" function, it is in the public ABI, so + * we can never remove it or change its signature. */ +svn_error_t * +svn_iter__break(void) +{ + return &internal_break_error; +} + +/* Note about the type casts: apr_hash_this() does not expect a const hash + * index pointer even though it does not modify the hash index. In + * Subversion we're trying to be const-correct, so these functions all take + * a const hash index and we cast away the const when passing it down to + * APR. (A compiler may warn about casting away 'const', but at least this + * cast is explicit and gathered in one place.) */ + +const void *svn__apr_hash_index_key(const apr_hash_index_t *hi) +{ + const void *key; + + apr_hash_this((apr_hash_index_t *)hi, &key, NULL, NULL); + return key; +} + +apr_ssize_t svn__apr_hash_index_klen(const apr_hash_index_t *hi) +{ + apr_ssize_t klen; + + apr_hash_this((apr_hash_index_t *)hi, NULL, &klen, NULL); + return klen; +} + +void *svn__apr_hash_index_val(const apr_hash_index_t *hi) +{ + void *val; + + apr_hash_this((apr_hash_index_t *)hi, NULL, NULL, &val); + return val; +} |