blob: c93698839a9b00bfc95e3559ba021ec17ae006db [file] [log] [blame]
/*
* sorts.c: all sorts of sorts
*
* ====================================================================
* Copyright (c) 2000-2002 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_tables.h>
#include <string.h> /* for strncmp() */
#include <stdlib.h> /* for qsort() */
#include "svn_string.h"
#include "svn_path.h"
#include "svn_sorts.h"
/*** apr_hash_sorted_keys() ***/
/* (Should this be a permanent part of APR?)
OK, folks, here's what's going on. APR hash tables hash on
key/klen objects, and store associated generic values. They work
great, but they have no ordering.
The point of this exercise is to somehow arrange a hash's keys into
an "ordered list" of some kind -- in this case, a nicely sorted
one.
We're using APR arrays, therefore, because that's what they are:
ordered lists. However, what "keys" should we put in the array?
Clearly, (const char *) objects aren't general enough. Or rather,
they're not as general as APR's hash implementation, which stores
(void *)/length as keys. We don't want to lose this information.
Therefore, it makes sense to store pointers to {void *, size_t}
structures in our array. No such apr object exists... BUT... if we
can use a new type svn_item_t which contains {char *, size_t, void
*}. If store these objects in our array, we get the hash value
*for free*. When looping over the final array, we don't need to
call apr_hash_get(). Major bonus!
*/
int
svn_sort_compare_items_as_paths (const svn_item_t *a, const svn_item_t *b)
{
svn_stringbuf_t str_a, str_b;
/* ### these are bogus! compare_paths ought to take svn_string_t */
str_a.data = (char *)a->key;
str_a.len = str_a.blocksize = a->klen;
str_a.pool = NULL;
str_b.data = (char *)b->key;
str_b.len = str_b.blocksize = b->klen;
str_b.pool = NULL;
return svn_path_compare_paths (&str_a, &str_b);
}
int
svn_sort_compare_strings_as_paths (const void *a, const void *b)
{
const svn_stringbuf_t *str_a = *((svn_stringbuf_t **) a);
const svn_stringbuf_t *str_b = *((svn_stringbuf_t **) b);
return svn_path_compare_paths (str_a, str_b);
}
int
svn_sort_compare_revisions (const void *a, const void *b)
{
svn_revnum_t a_rev = *(svn_revnum_t *)a;
svn_revnum_t b_rev = *(svn_revnum_t *)b;
if (a_rev == b_rev)
return 0;
return a_rev < b_rev ? 1 : -1;
}
#ifndef apr_hash_sort_keys
/* see svn_sorts.h for documentation */
apr_array_header_t *
apr_hash_sorted_keys (apr_hash_t *ht,
int (*comparison_func) (const svn_item_t *,
const svn_item_t *),
apr_pool_t *pool)
{
apr_hash_index_t *hi;
apr_array_header_t *ary;
/* allocate an array with only one element to begin with. */
ary = apr_array_make (pool, 1, sizeof(svn_item_t));
/* loop over hash table and push all keys into the array */
for (hi = apr_hash_first (pool, ht); hi; hi = apr_hash_next (hi))
{
svn_item_t *item = apr_array_push (ary);
apr_hash_this (hi, &item->key, &item->klen, &item->value);
}
/* now quicksort the array. */
qsort (ary->elts, ary->nelts, ary->elt_size,
(int (*)(const void *, const void *))comparison_func);
return ary;
}
#endif /* apr_hash_sort_keys */
/** Sorting properties **/
enum svn_prop_kind
svn_property_kind (int *prefix_len,
const char *prop_name)
{
apr_size_t wc_prefix_len = sizeof (SVN_PROP_WC_PREFIX) - 1;
apr_size_t entry_prefix_len = sizeof (SVN_PROP_ENTRY_PREFIX) - 1;
if (strncmp (prop_name, SVN_PROP_WC_PREFIX, wc_prefix_len) == 0)
{
*prefix_len = wc_prefix_len;
return svn_prop_wc_kind;
}
if (strncmp (prop_name, SVN_PROP_ENTRY_PREFIX, entry_prefix_len) == 0)
{
*prefix_len = entry_prefix_len;
return svn_prop_entry_kind;
}
/* else... */
*prefix_len = 0;
return svn_prop_regular_kind;
}
svn_error_t *
svn_categorize_props (const apr_array_header_t *proplist,
apr_array_header_t **entry_props,
apr_array_header_t **wc_props,
apr_array_header_t **regular_props,
apr_pool_t *pool)
{
int i, len;
*entry_props = apr_array_make (pool, 1, sizeof(svn_prop_t));
*wc_props = apr_array_make (pool, 1, sizeof(svn_prop_t));
*regular_props = apr_array_make (pool, 1, sizeof(svn_prop_t));
for (i = 0; i < proplist->nelts; i++)
{
svn_prop_t *prop, *newprop;
enum svn_prop_kind kind;
prop = &APR_ARRAY_IDX(proplist, i, svn_prop_t);
kind = svn_property_kind (&len, prop->name);
if (kind == svn_prop_regular_kind)
newprop = apr_array_push (*regular_props);
else if (kind == svn_prop_wc_kind)
newprop = apr_array_push (*wc_props);
else if (kind == svn_prop_entry_kind)
newprop = apr_array_push (*entry_props);
else
return svn_error_createf (SVN_ERR_UNKNOWN_PROP_KIND, 0, NULL, pool,
"svn_categorize_props: unknown prop kind "
"for property '%s'", prop->name);
newprop->name = prop->name;
newprop->value = prop->value;
}
return SVN_NO_ERROR;
}
/*
* local variables:
* eval: (load-file "../../tools/dev/svn-dev.el")
* end:
*/