Change the format of the revprops block sent in svnserve for
[svn.git] / subversion / libsvn_subr / properties.c
blob5b68c342f8e19d3c48e4da778fd520859a13fa77
1 /*
2 * properties.c: stuff related to Subversion properties
4 * ====================================================================
5 * Copyright (c) 2000-2006 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
21 #include <apr_pools.h>
22 #include <apr_hash.h>
23 #include <apr_tables.h>
24 #include <string.h> /* for strncmp() */
25 #include <assert.h>
26 #include "svn_string.h"
27 #include "svn_props.h"
28 #include "svn_error.h"
29 #include "svn_ctype.h"
32 svn_boolean_t
33 svn_prop_is_svn_prop(const char *prop_name)
35 return strncmp(prop_name, SVN_PROP_PREFIX, (sizeof(SVN_PROP_PREFIX) - 1))
36 ? FALSE
37 : TRUE;
41 svn_boolean_t
42 svn_prop_has_svn_prop(apr_hash_t *props, apr_pool_t *pool)
44 apr_hash_index_t *hi;
45 const void *prop_name;
47 if (! props)
48 return FALSE;
50 for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
52 apr_hash_this(hi, &prop_name, NULL, NULL);
53 if (svn_prop_is_svn_prop((const char *) prop_name))
54 return TRUE;
57 return FALSE;
61 svn_prop_kind_t
62 svn_property_kind(int *prefix_len,
63 const char *prop_name)
65 apr_size_t wc_prefix_len = sizeof(SVN_PROP_WC_PREFIX) - 1;
66 apr_size_t entry_prefix_len = sizeof(SVN_PROP_ENTRY_PREFIX) - 1;
68 if (strncmp(prop_name, SVN_PROP_WC_PREFIX, wc_prefix_len) == 0)
70 if (prefix_len)
71 *prefix_len = wc_prefix_len;
72 return svn_prop_wc_kind;
75 if (strncmp(prop_name, SVN_PROP_ENTRY_PREFIX, entry_prefix_len) == 0)
77 if (prefix_len)
78 *prefix_len = entry_prefix_len;
79 return svn_prop_entry_kind;
82 /* else... */
83 if (prefix_len)
84 *prefix_len = 0;
85 return svn_prop_regular_kind;
89 svn_error_t *
90 svn_categorize_props(const apr_array_header_t *proplist,
91 apr_array_header_t **entry_props,
92 apr_array_header_t **wc_props,
93 apr_array_header_t **regular_props,
94 apr_pool_t *pool)
96 int i;
97 if (entry_props)
98 *entry_props = apr_array_make(pool, 1, sizeof(svn_prop_t));
99 if (wc_props)
100 *wc_props = apr_array_make(pool, 1, sizeof(svn_prop_t));
101 if (regular_props)
102 *regular_props = apr_array_make(pool, 1, sizeof(svn_prop_t));
104 for (i = 0; i < proplist->nelts; i++)
106 svn_prop_t *prop, *newprop;
107 enum svn_prop_kind kind;
109 prop = &APR_ARRAY_IDX(proplist, i, svn_prop_t);
110 kind = svn_property_kind(NULL, prop->name);
111 newprop = NULL;
113 if (kind == svn_prop_regular_kind)
115 if (regular_props)
116 newprop = apr_array_push(*regular_props);
118 else if (kind == svn_prop_wc_kind)
120 if (wc_props)
121 newprop = apr_array_push(*wc_props);
123 else if (kind == svn_prop_entry_kind)
125 if (entry_props)
126 newprop = apr_array_push(*entry_props);
128 else
129 /* Technically this can't happen, but might as well have the
130 code ready in case that ever changes. */
131 return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL,
132 "Bad property kind for property '%s'",
133 prop->name);
135 if (newprop)
137 newprop->name = prop->name;
138 newprop->value = prop->value;
142 return SVN_NO_ERROR;
146 svn_error_t *
147 svn_prop_diffs(apr_array_header_t **propdiffs,
148 apr_hash_t *target_props,
149 apr_hash_t *source_props,
150 apr_pool_t *pool)
152 apr_hash_index_t *hi;
153 apr_array_header_t *ary = apr_array_make(pool, 1, sizeof(svn_prop_t));
155 /* Note: we will be storing the pointers to the keys (from the hashes)
156 into the propdiffs array. It is acceptable for us to
157 reference the same memory as the base/target_props hash. */
159 /* Loop over SOURCE_PROPS and examine each key. This will allow us to
160 detect any `deletion' events or `set-modification' events. */
161 for (hi = apr_hash_first(pool, source_props); hi; hi = apr_hash_next(hi))
163 const void *key;
164 apr_ssize_t klen;
165 void *val;
166 const svn_string_t *propval1, *propval2;
168 /* Get next property */
169 apr_hash_this(hi, &key, &klen, &val);
170 propval1 = val;
172 /* Does property name exist in TARGET_PROPS? */
173 propval2 = apr_hash_get(target_props, key, klen);
175 if (propval2 == NULL)
177 /* Add a delete event to the array */
178 svn_prop_t *p = apr_array_push(ary);
179 p->name = key;
180 p->value = NULL;
182 else if (! svn_string_compare(propval1, propval2))
184 /* Add a set (modification) event to the array */
185 svn_prop_t *p = apr_array_push(ary);
186 p->name = key;
187 p->value = svn_string_dup(propval2, pool);
191 /* Loop over TARGET_PROPS and examine each key. This allows us to
192 detect `set-creation' events */
193 for (hi = apr_hash_first(pool, target_props); hi; hi = apr_hash_next(hi))
195 const void *key;
196 apr_ssize_t klen;
197 void *val;
198 const svn_string_t *propval;
200 /* Get next property */
201 apr_hash_this(hi, &key, &klen, &val);
202 propval = val;
204 /* Does property name exist in SOURCE_PROPS? */
205 if (NULL == apr_hash_get(source_props, key, klen))
207 /* Add a set (creation) event to the array */
208 svn_prop_t *p = apr_array_push(ary);
209 p->name = key;
210 p->value = svn_string_dup(propval, pool);
214 /* Done building our array of user events. */
215 *propdiffs = ary;
217 return SVN_NO_ERROR;
221 svn_boolean_t
222 svn_prop_is_boolean(const char *prop_name)
224 /* If we end up with more than 3 of these, we should probably put
225 them in a table and use bsearch. With only three, it doesn't
226 make any speed difference. */
227 if (strcmp(prop_name, SVN_PROP_EXECUTABLE) == 0
228 || strcmp(prop_name, SVN_PROP_NEEDS_LOCK) == 0
229 || strcmp(prop_name, SVN_PROP_SPECIAL) == 0)
230 return TRUE;
231 return FALSE;
235 svn_boolean_t
236 svn_prop_needs_translation(const char *propname)
238 /* ### Someday, we may want to be picky and choosy about which
239 properties require UTF8 and EOL conversion. For now, all "svn:"
240 props need it. */
242 return svn_prop_is_svn_prop(propname);
246 svn_boolean_t
247 svn_prop_name_is_valid(const char *prop_name)
249 const char *p = prop_name;
251 /* The characters we allow use identical representations in UTF8
252 and ASCII, so we can just test for the appropriate ASCII codes.
253 But we can't use standard C character notation ('A', 'B', etc)
254 because there's no guarantee that this C environment is using
255 ASCII. */
257 if (!(svn_ctype_isalpha(*p)
258 || *p == SVN_CTYPE_ASCII_COLON
259 || *p == SVN_CTYPE_ASCII_UNDERSCORE))
260 return FALSE;
261 p++;
262 for (; *p; p++)
264 if (!(svn_ctype_isalnum(*p)
265 || *p == SVN_CTYPE_ASCII_MINUS
266 || *p == SVN_CTYPE_ASCII_DOT
267 || *p == SVN_CTYPE_ASCII_COLON
268 || *p == SVN_CTYPE_ASCII_UNDERSCORE))
269 return FALSE;
271 return TRUE;