I've taken a different tack with the proposed Keywords as Hash patch. Phase 1,
attached, changes only libsvn_subr/svn_subst.c (and associated include files)
and leave all of the rest of the core files untouched. This meant I could
create and test the API compatibility layer independently of the changes to the
remaining files.
Phase 2 will be to convert the remainder of the Subversion code to use the
generation 2 function calls directly, while still maintaining API compatibility.
Both Phases 1 & 2 will be candidates for 1.1.
Phase 3 will be to propose the new functionality of custom Keywords from
Properties, and will be wholely independent of the previous 2 phases.
John
=================
Implement printf-like format characters for keyword expansion. See
Issue #890 for further information.
* includes/svn_subst.h:
(struct svn_subst_keywords_t): Add svn_subst_keyhash_t
(svn_subst_build_keywords2): Interface change. A new argument
apr_hash_t *props.
(svn_subst_build_keywords): API compatibility wrapper for previous
(svn_subst_keywords_differ2): Interface change. A new argument
apr_pool_t *pool.
(svn_subst_keywords_differ): API compatibility wrapper for previous
(svn_subst_copy_and_translate2): Interface change; hash instead of struct
(svn_subst_copy_and_translate): API compatibility wrapper for previous
(svn_subst_translate_stream2): Interface change; hash instead of struct
(svn_subst_translate_stream): API compatibility wrapper for previous
* includes/svn_types.h:
Define keyword format string for Revision, Date, Author, URL, ID
* libsvn_subr/svn_subst.c:
(keyword_printf): New private function; printf-style formatting of
keywords based on format strings
(keywords_to_keyhash): New private function; convert keywords struct into
keywords hash
(keyhash_to_keywords): New private function; convert keywords hash into
keywords struct
(svn_subst_build_keywords): API combatibility wrapper
(svn_subst_build_keywords2): Build keywords using keyword_printf().
(translate_keyword): Interface changes. It now looks up keyword
passed in buffer, instead of predefined constant string.
(svn_subst_translate_stream): API combatibility wrapper
(svn_subst_translate_stream2): Loop over all elements of keyword hash
instead of structure elements.
(svn_subst_keywords_differ): API combatibility wrapper
(svn_subst_keywords_differ2): Compare two hashes instead of comparing
individual structure elements.
(svn_subst_copy_and_translate): API combatibility wrapper
(svn_subst_copy_and_translate2): uses keywords hash instead of struct
--
John Peacock
Director of Information Research and Technology
Rowman & Littlefield Publishing Group
4720 Boston Way
Lanham, MD 20706
301-459-3366 x.5010
fax 301-429-5747
Index: subversion/include/svn_subst.h
==================================================================
--- subversion/include/svn_subst.h (/svn/trunk) (revision 8680)
+++ subversion/include/svn_subst.h (/svn/local/keywords-phase-1) (revision 8680)
@@ -76,6 +76,11 @@
/** Values used in keyword expansion. */
+typedef apr_hash_t svn_subst_keyhash_t;
+
+/* struct svn_subst_keywords_t is @deprecated
+ * Provided for backward compatibility with the 1.0.0 API.
+ */
typedef struct svn_subst_keywords_t
{
const svn_string_t *revision;
@@ -85,8 +90,7 @@
const svn_string_t *id;
} svn_subst_keywords_t;
-
-/** Fill in an <tt>svn_subst_keywords_t *</tt> @a kw with the appropriate
+/** Fill in an <tt>svn_subst_keyhash_t *</tt> @a kw with the appropriate
* contents given an @a keywords_string (the contents of the svn:keywords
* property for the file in question), the revision @a rev, the @a url,
* the @a date the file was committed on, and the @a author of the last
@@ -96,6 +100,21 @@
* All memory is allocated out of @a pool.
*/
svn_error_t *
+svn_subst_build_keywords2 (svn_subst_keyhash_t *kw,
+ const char *keywords_string,
+ const char *rev,
+ const char *url,
+ apr_time_t date,
+ const char *author,
+ apr_hash_t *props,
+ apr_pool_t *pool);
+
+/** Similar to svn_subst_build_keywords2(); does not handle possible property
+ * keywords.
+ *
+ * @deprecated Provided for backward compatibility with the 1.0.0 API.
+ */
+svn_error_t *
svn_subst_build_keywords (svn_subst_keywords_t *kw,
const char *keywords_string,
const char *rev,
@@ -104,7 +123,6 @@
const char *author,
apr_pool_t *pool);
-
/** Return @c TRUE if @a a and @a b do not hold the same keywords.
*
* If @a compare_values is @c TRUE, "same" means that the @a a and @a b
@@ -117,11 +135,23 @@
* equivalent to holding no keywords.
*/
svn_boolean_t
+svn_subst_keywords_differ2 (const svn_subst_keyhash_t *a,
+ const svn_subst_keyhash_t *b,
+ svn_boolean_t compare_values,
+ apr_pool_t *pool);
+
+/** Return @c TRUE if @a a and @a b do not hold the same keywords.
+ *
+ * Similar to svn_subst_keywords_differ2(); provides a pool for performing
+ * the hash comparisons.
+ *
+ * @deprecated Provided for backward compatibility with the 1.0.0 API.
+ */
+svn_boolean_t
svn_subst_keywords_differ (const svn_subst_keywords_t *a,
const svn_subst_keywords_t *b,
svn_boolean_t compare_values);
-
/** Copy and translate the data in stream @a src into stream @a dst. It is
* assumed that @a src is a readable stream and @a dst is a writable stream.
*
@@ -155,6 +185,18 @@
* convenient way to get @a eol_str and @a keywords if in libsvn_wc.
*/
svn_error_t *
+svn_subst_translate_stream2 (svn_stream_t *s, /* src stream */
+ svn_stream_t *d, /* dst stream */
+ const char *eol_str,
+ svn_boolean_t repair,
+ svn_subst_keyhash_t *keywords,
+ svn_boolean_t expand);
+
+/** Similar to svn_subst_translate_stream2()
+ *
+ * @deprecated Provided for backward compatibility with the 1.0.0 API.
+ */
+svn_error_t *
svn_subst_translate_stream (svn_stream_t *src,
svn_stream_t *dst,
const char *eol_str,
@@ -162,7 +204,6 @@
const svn_subst_keywords_t *keywords,
svn_boolean_t expand);
-
/** Convenience routine: a variant of @c svn_subst_translate_stream which
* operates on files. (See previous docstring for details.)
*
@@ -175,6 +216,19 @@
*
* If @a eol_str and @a keywords are @c NULL, behavior is just a byte-for-byte
* copy.
+ */
+svn_error_t *
+svn_subst_copy_and_translate2 (const char *src,
+ const char *dst,
+ const char *eol_str,
+ svn_boolean_t repair,
+ svn_subst_keyhash_t *keywords,
+ svn_boolean_t expand,
+ apr_pool_t *pool);
+
+/** Similar to svn_subst_copy_and_translate2()
+ *
+ * @deprecated Provided for backward compatibility with the 1.0.0 API.
*/
svn_error_t *
svn_subst_copy_and_translate (const char *src,
Index: subversion/include/svn_types.h
==================================================================
--- subversion/include/svn_types.h (/svn/trunk) (revision 8680)
+++ subversion/include/svn_types.h (/svn/local/keywords-phase-1) (revision 8680)
@@ -219,30 +219,45 @@
/** Short version of LastChangedRevision */
#define SVN_KEYWORD_REVISION_SHORT "Rev"
+/** Format string for Revision */
+#define SVN_KEYWORD_REVISION_FORMAT "%r"
+
/** The most recent date (repository time) when this file was changed. */
#define SVN_KEYWORD_DATE_LONG "LastChangedDate"
/** Short version of LastChangedDate */
#define SVN_KEYWORD_DATE_SHORT "Date"
+/** Format string for Date */
+#define SVN_KEYWORD_DATE_FORMAT "%D"
+
/** Who most recently committed to this file. */
#define SVN_KEYWORD_AUTHOR_LONG "LastChangedBy"
/** Short version of LastChangedBy */
#define SVN_KEYWORD_AUTHOR_SHORT "Author"
+/** Format string for Author */
+#define SVN_KEYWORD_AUTHOR_FORMAT "%a"
+
/** The URL for the head revision of this file. */
#define SVN_KEYWORD_URL_LONG "HeadURL"
/** Short version of HeadURL */
#define SVN_KEYWORD_URL_SHORT "URL"
+/** Format string for Author */
+#define SVN_KEYWORD_URL_FORMAT "%u"
+
/** A compressed combination of the other four keywords.
*
* (But see comments above about a more general solution to keyword
* combinations.)
*/
#define SVN_KEYWORD_ID "Id"
+
+/** Format string for ID */
+#define SVN_KEYWORD_ID_FORMAT "%b %d %a %r"
/** @} */
Index: subversion/libsvn_subr/subst.c
==================================================================
--- subversion/libsvn_subr/subst.c (/svn/trunk) (revision 8680)
+++ subversion/libsvn_subr/subst.c (/svn/local/keywords-phase-1) (revision 8680)
@@ -114,6 +114,200 @@
return SVN_NO_ERROR;
}
+
+/* Helper function for svn_subst_build_keywords */
+
+/** Given a printf-like format string, return a string with proper
+ * information filled in.
+ *
+ * The codes of format:
+ *
+ * %a author of this revision
+ * %b basename of the URL of this file
+ * %d short format of date of this revision
+ * %D long format of date of this revision
+ * %p property value
+ * %r number of this revision
+ * %u URL of this file
+ *
+ * All memory is allocated out of @a pool.
+ */
+static svn_string_t *
+keyword_printf (const char *fmt,
+ const char *rev,
+ const char *url,
+ apr_time_t date,
+ const char *author,
+ apr_hash_t *props,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *value = svn_stringbuf_ncreate ("", 0, pool);
+ const char *cur;
+ char ch;
+ int n;
+
+ for (;;)
+ {
+ for (cur = fmt; (ch = *cur) != '\0' && ch != '%'; cur++)
+ /* void */;
+ if ( (n = cur - fmt) > 0) /* Do we have a as-is string? */
+ svn_stringbuf_appendbytes (value, fmt, n);
+
+ if (ch == '\0')
+ break;
+
+ cur++; /* skip '%' */
+ ch = *cur++;
+ switch (ch)
+ {
+ case 'a': /* author of this revision */
+ if (author)
+ svn_stringbuf_appendcstr (value, author);
+ break;
+ case 'b': /* basename of this file */
+ if (url)
+ {
+ const char *base_name = NULL;
+ base_name = svn_path_basename (url, pool);
+
+ svn_stringbuf_appendcstr (value, base_name);
+ }
+ break;
+ case 'd': /* short format of date of this revision */
+ if (date)
+ {
+ const char *human_date = NULL;
+
+ if (!date_prop_to_human (&human_date, FALSE, date, pool))
+ svn_stringbuf_appendcstr (value, human_date);
+ }
+ break;
+ case 'D': /* long format of date of this revision */
+ if (date)
+ {
+ const char *human_date = NULL;
+
+ if (!date_prop_to_human (&human_date, TRUE, date, pool))
+ svn_stringbuf_appendcstr (value, human_date);
+ }
+ break;
+ case 'p': /* property value */
+ /* Fetch property name */
+ if (*cur != '(') /* Invalid format */
+ break;
+ for (fmt = ++cur; (ch = *cur) != '\0' && ch != ')'; cur++)
+ /* void */;
+ if (ch == '\0') /* Invalid format, rewind. */
+ {
+ cur = fmt - 1;
+ break;
+ }
+ /* Look up in props hash*/
+ if (props)
+ {
+ svn_string_t *prop_val;
+ prop_val = apr_hash_get(props, fmt, cur - fmt);
+ /* do no harm if they didn't include that property */
+ if ( prop_val )
+ svn_stringbuf_appendcstr (value, prop_val->data);
+ }
+ cur++;
+ break;
+ case 'r': /* number of this revision */
+ if (rev)
+ svn_stringbuf_appendcstr (value, rev);
+ break;
+ case 'u': /* URL of this file */
+ if (url)
+ svn_stringbuf_appendcstr (value, url);
+ break;
+ default: /* %?, print ? as is. */
+ svn_stringbuf_appendbytes (value, &ch, 1);
+ break;
+ }
+
+ /* Format code is processed. Get ready for next chunk. */
+ fmt = cur;
+ }
+
+ return svn_string_create_from_buf (value, pool);
+}
+
+/* Convert the old-style keywords struct into the new keywords hash */
+static svn_subst_keyhash_t *
+keywords_to_keyhash (svn_subst_keywords_t *kw,
+ apr_pool_t *pool)
+{
+ svn_subst_keyhash_t *khash = apr_hash_make(pool);
+
+ /* if there are no keywords set, just return immediately */
+ if (kw == NULL)
+ return khash;
+
+ if (kw->revision)
+ {
+ apr_hash_set (khash, SVN_KEYWORD_REVISION_LONG,
+ APR_HASH_KEY_STRING, kw->revision);
+ apr_hash_set (khash, SVN_KEYWORD_REVISION_SHORT,
+ APR_HASH_KEY_STRING, kw->revision);
+ }
+ if (kw->date)
+ {
+ apr_hash_set (khash, SVN_KEYWORD_DATE_LONG,
+ APR_HASH_KEY_STRING, kw->date);
+ apr_hash_set (khash, SVN_KEYWORD_DATE_SHORT,
+ APR_HASH_KEY_STRING, kw->date);
+ }
+ if (kw->author)
+ {
+ apr_hash_set (khash, SVN_KEYWORD_AUTHOR_LONG,
+ APR_HASH_KEY_STRING, kw->author);
+ apr_hash_set (khash, SVN_KEYWORD_AUTHOR_SHORT,
+ APR_HASH_KEY_STRING, kw->author);
+ }
+ if (kw->url)
+ {
+ apr_hash_set (khash, SVN_KEYWORD_URL_LONG,
+ APR_HASH_KEY_STRING, kw->url);
+ apr_hash_set (khash, SVN_KEYWORD_URL_SHORT,
+ APR_HASH_KEY_STRING, kw->url);
+ }
+ if (kw->id)
+ {
+ apr_hash_set (khash, SVN_KEYWORD_ID,
+ APR_HASH_KEY_STRING, kw->id);
+ }
+
+ return khash;
+}
+
+/* Convert new style keyhash into keyword struct */
+static void
+keyhash_to_keywords (svn_subst_keywords_t *kw,
+ svn_subst_keyhash_t *khash,
+ apr_pool_t *pool)
+{
+ /* Attempt to fill all of the default keyword slots
+ * In each case, if the hash doesn't contain the corresponding
+ * keyword value, the struct element will be null
+ */
+
+ kw->revision = apr_hash_get(khash, SVN_KEYWORD_REVISION_LONG,
+ APR_HASH_KEY_STRING);
+
+ kw->date = apr_hash_get(khash, SVN_KEYWORD_DATE_LONG,
+ APR_HASH_KEY_STRING);
+
+ kw->author = apr_hash_get(khash, SVN_KEYWORD_AUTHOR_LONG,
+ APR_HASH_KEY_STRING);
+
+ kw->url = apr_hash_get(khash, SVN_KEYWORD_URL_LONG,
+ APR_HASH_KEY_STRING);
+
+ kw->id = apr_hash_get(khash, SVN_KEYWORD_ID,
+ APR_HASH_KEY_STRING);
+}
+
svn_error_t *
svn_subst_build_keywords (svn_subst_keywords_t *kw,
const char *keywords_val,
@@ -123,6 +317,27 @@
const char *author,
apr_pool_t *pool)
{
+ svn_subst_keyhash_t *khash = apr_hash_make(pool);
+
+ svn_error_t * kerror = svn_subst_build_keywords2(khash, keywords_val, rev,
+ url, date, author, NULL,
+ pool);
+
+ keyhash_to_keywords(kw, khash, pool);
+
+ return kerror;
+}
+
+svn_error_t *
+svn_subst_build_keywords2 (svn_subst_keyhash_t *kw,
+ const char *keywords_val,
+ const char *rev,
+ const char *url,
+ apr_time_t date,
+ const char *author,
+ apr_hash_t *props,
+ apr_pool_t *pool)
+{
apr_array_header_t *keyword_tokens;
int i;
@@ -136,46 +351,84 @@
if ((! strcmp (keyword, SVN_KEYWORD_REVISION_LONG))
|| (! strcasecmp (keyword, SVN_KEYWORD_REVISION_SHORT)))
{
- kw->revision = svn_string_create (rev, pool);
- }
+ svn_string_t *revision_val;
+
+ revision_val = keyword_printf (SVN_KEYWORD_REVISION_FORMAT,
+ rev, url, date, author,
+ props, pool);
+ apr_hash_set (kw, SVN_KEYWORD_REVISION_LONG,
+ APR_HASH_KEY_STRING, revision_val);
+ apr_hash_set (kw, SVN_KEYWORD_REVISION_SHORT,
+ APR_HASH_KEY_STRING, revision_val);
+ }
else if ((! strcmp (keyword, SVN_KEYWORD_DATE_LONG))
|| (! strcasecmp (keyword, SVN_KEYWORD_DATE_SHORT)))
{
if (date)
{
- const char *human_date;
+ svn_string_t *date_val;
- SVN_ERR (date_prop_to_human (&human_date, TRUE, date, pool));
-
- kw->date = svn_string_create (human_date, pool);
+ date_val = keyword_printf (SVN_KEYWORD_DATE_FORMAT,
+ rev, url, date, author,
+ props, pool);
+ apr_hash_set (kw, SVN_KEYWORD_DATE_LONG,
+ APR_HASH_KEY_STRING, date_val);
+ apr_hash_set (kw, SVN_KEYWORD_DATE_SHORT,
+ APR_HASH_KEY_STRING, date_val);
}
else
- kw->date = svn_string_create ("", pool);
+ {
+ svn_string_t *date_val;
+
+ date_val = svn_string_create ("", pool);
+ apr_hash_set (kw, SVN_KEYWORD_DATE_LONG,
+ APR_HASH_KEY_STRING, date_val);
+ apr_hash_set (kw, SVN_KEYWORD_DATE_SHORT,
+ APR_HASH_KEY_STRING, date_val);
+ }
}
else if ((! strcmp (keyword, SVN_KEYWORD_AUTHOR_LONG))
|| (! strcasecmp (keyword, SVN_KEYWORD_AUTHOR_SHORT)))
{
- kw->author = svn_string_create (author ? author : "", pool);
+ svn_string_t *author_val;
+
+ author_val = keyword_printf (SVN_KEYWORD_AUTHOR_FORMAT,
+ rev, url, date, author,
+ props, pool);
+ apr_hash_set (kw, SVN_KEYWORD_AUTHOR_LONG,
+ APR_HASH_KEY_STRING, author_val);
+ apr_hash_set (kw, SVN_KEYWORD_AUTHOR_SHORT,
+ APR_HASH_KEY_STRING, author_val);
}
else if ((! strcmp (keyword, SVN_KEYWORD_URL_LONG))
|| (! strcasecmp (keyword, SVN_KEYWORD_URL_SHORT)))
{
- kw->url = svn_string_create (url ? url : "", pool);
+ svn_string_t *url_val;
+
+ url_val = keyword_printf (SVN_KEYWORD_URL_FORMAT,
+ rev, url, date, author,
+ props, pool);
+ apr_hash_set (kw, SVN_KEYWORD_URL_LONG,
+ APR_HASH_KEY_STRING, url_val);
+ apr_hash_set (kw, SVN_KEYWORD_URL_SHORT,
+ APR_HASH_KEY_STRING, url_val);
}
else if ((! strcasecmp (keyword, SVN_KEYWORD_ID)))
{
const char *base_name = url ? svn_path_basename (url, pool) : "";
const char *human_date = NULL;
+ svn_string_t *id_val;
- if (date)
- SVN_ERR (date_prop_to_human (&human_date, FALSE, date, pool));
-
- kw->id = svn_string_createf (pool, "%s %s %s %s",
- base_name,
- rev,
- human_date ? human_date : "",
- author ? author : "");
+ id_val = keyword_printf (SVN_KEYWORD_ID_FORMAT,
+ rev, url, date, author,
+ props, pool);
+ apr_hash_set (kw, SVN_KEYWORD_ID,
+ APR_HASH_KEY_STRING, id_val);
}
+ /* Whenever server-side configuration is developed, a test could be
+ * placed here to check and see if one of the repository-defined
+ * keywords matches
+ */
}
return SVN_NO_ERROR;
@@ -329,8 +582,15 @@
translate_keyword (char *buf,
apr_size_t *len,
svn_boolean_t expand,
- const svn_subst_keywords_t *keywords)
+ const svn_subst_keyhash_t *keywords)
{
+ const svn_string_t *value;
+ char key[SVN_KEYWORD_MAX_LEN + 1];
+ svn_subst_keyhash_t *lame_keywords;
+ int i;
+
+ lame_keywords = (svn_subst_keyhash_t *) keywords;
+
/* Make sure we gotz good stuffs. */
assert (*len <= SVN_KEYWORD_MAX_LEN);
assert ((buf[0] == '$') && (buf[*len - 1] == '$'));
@@ -339,81 +599,20 @@
if (! keywords)
return FALSE;
- /* Revision */
- if (keywords->revision)
- {
- if (translate_keyword_subst (buf, len,
- SVN_KEYWORD_REVISION_LONG,
- (sizeof (SVN_KEYWORD_REVISION_LONG)) - 1,
- expand ? keywords->revision : NULL))
- return TRUE;
+ for (i = 0; i < *len - 2 && buf[i + 1] != ':'; i++)
+ key[i] = *(buf + i + 1);
+ key[i] = 0;
- if (translate_keyword_subst (buf, len,
- SVN_KEYWORD_REVISION_SHORT,
- (sizeof (SVN_KEYWORD_REVISION_SHORT)) - 1,
- expand ? keywords->revision : NULL))
- return TRUE;
- }
+ value = apr_hash_get (lame_keywords, key, APR_HASH_KEY_STRING);
- /* Date */
- if (keywords->date)
+ if (value)
{
if (translate_keyword_subst (buf, len,
- SVN_KEYWORD_DATE_LONG,
- (sizeof (SVN_KEYWORD_DATE_LONG)) - 1,
- expand ? keywords->date : NULL))
+ key, strlen(key),
+ expand ? value : NULL))
return TRUE;
-
- if (translate_keyword_subst (buf, len,
- SVN_KEYWORD_DATE_SHORT,
- (sizeof (SVN_KEYWORD_DATE_SHORT)) - 1,
- expand ? keywords->date : NULL))
- return TRUE;
}
- /* Author */
- if (keywords->author)
- {
- if (translate_keyword_subst (buf, len,
- SVN_KEYWORD_AUTHOR_LONG,
- (sizeof (SVN_KEYWORD_AUTHOR_LONG)) - 1,
- expand ? keywords->author : NULL))
- return TRUE;
-
- if (translate_keyword_subst (buf, len,
- SVN_KEYWORD_AUTHOR_SHORT,
- (sizeof (SVN_KEYWORD_AUTHOR_SHORT)) - 1,
- expand ? keywords->author : NULL))
- return TRUE;
- }
-
- /* URL */
- if (keywords->url)
- {
- if (translate_keyword_subst (buf, len,
- SVN_KEYWORD_URL_LONG,
- (sizeof (SVN_KEYWORD_URL_LONG)) - 1,
- expand ? keywords->url : NULL))
- return TRUE;
-
- if (translate_keyword_subst (buf, len,
- SVN_KEYWORD_URL_SHORT,
- (sizeof (SVN_KEYWORD_URL_SHORT)) - 1,
- expand ? keywords->url : NULL))
- return TRUE;
- }
-
- /* Id */
- if (keywords->id)
- {
- if (translate_keyword_subst (buf, len,
- SVN_KEYWORD_ID,
- (sizeof (SVN_KEYWORD_ID)) - 1,
- expand ? keywords->id : NULL))
- return TRUE;
- }
-
- /* No translations were successful. Return FALSE. */
return FALSE;
}
@@ -464,7 +663,6 @@
return translate_write (dst, eol_str, eol_str_len);
}
-
/*** Public interfaces. ***/
@@ -473,66 +671,61 @@
const svn_subst_keywords_t *b,
svn_boolean_t compare_values)
{
+ svn_boolean_t result = FALSE;
+ apr_pool_t *pool = svn_pool_create (NULL);
+
+ /* first we have to create a hash of each of the keyword struct's */
+ svn_subst_keyhash_t *ahash = keywords_to_keyhash((svn_subst_keywords_t *)a,
+ pool);
+ svn_subst_keyhash_t *bhash = keywords_to_keyhash((svn_subst_keywords_t *)b,
+ pool);
+
+ /* and then call the real function */
+ result = svn_subst_keywords_differ2 (ahash,bhash,compare_values,pool);
+
+ /* Always clean up after ourselves */
+ svn_pool_destroy (pool);
+ return result;
+}
+
+svn_boolean_t
+svn_subst_keywords_differ2 (const svn_subst_keyhash_t *a,
+ const svn_subst_keyhash_t *b,
+ svn_boolean_t compare_values,
+ apr_pool_t *pool)
+{
+ svn_boolean_t result = FALSE;
+ apr_hash_index_t *hi;
+ svn_subst_keyhash_t *lame_a, *lame_b;
+
+ lame_a = (svn_subst_keyhash_t *) a;
+ lame_b = (svn_subst_keyhash_t *) b;
+
if (((a == NULL) && (b == NULL)) /* no A or B */
- /* no A, and B has no contents */
- || ((a == NULL)
- && (b->revision == NULL)
- && (b->date == NULL)
- && (b->author == NULL)
- && (b->url == NULL))
- /* no B, and A has no contents */
- || ((b == NULL) && (a->revision == NULL)
- && (a->date == NULL)
- && (a->author == NULL)
- && (a->url == NULL))
- /* neither A nor B has any contents */
- || ((a != NULL) && (b != NULL)
- && (b->revision == NULL)
- && (b->date == NULL)
- && (b->author == NULL)
- && (b->url == NULL)
- && (a->revision == NULL)
- && (a->date == NULL)
- && (a->author == NULL)
- && (a->url == NULL)))
+ /* Unequal number of contents */
+ || (apr_hash_count(lame_a) != apr_hash_count(lame_b)))
+ return TRUE;
+
+ /* If compare_values is FALSE, we can say A and B are the same now. */
+ if (!compare_values)
+ return FALSE;
+
+ /* compare_values is TRUE. Compare value by value */
+ for (hi = apr_hash_first(pool, lame_a);
+ hi && !result;
+ hi = apr_hash_next(hi))
{
- return FALSE;
+ const char *key;
+
+ apr_hash_this (hi, (const void**) &key, NULL, NULL);
+ if (!svn_string_compare (apr_hash_get (lame_a, key, APR_HASH_KEY_STRING),
+ apr_hash_get (lame_b, key, APR_HASH_KEY_STRING)))
+ result = TRUE;
}
- else if ((a == NULL) || (b == NULL))
- return TRUE;
-
- /* Else both A and B have some keywords. */
-
- if ((! a->revision) != (! b->revision))
- return TRUE;
- else if ((compare_values && (a->revision != NULL))
- && (strcmp (a->revision->data, b->revision->data) != 0))
- return TRUE;
-
- if ((! a->date) != (! b->date))
- return TRUE;
- else if ((compare_values && (a->date != NULL))
- && (strcmp (a->date->data, b->date->data) != 0))
- return TRUE;
-
- if ((! a->author) != (! b->author))
- return TRUE;
- else if ((compare_values && (a->author != NULL))
- && (strcmp (a->author->data, b->author->data) != 0))
- return TRUE;
-
- if ((! a->url) != (! b->url))
- return TRUE;
- else if ((compare_values && (a->url != NULL))
- && (strcmp (a->url->data, b->url->data) != 0))
- return TRUE;
-
- /* Else we never found a difference, so they must be the same. */
-
- return FALSE;
+
+ return result;
}
-
svn_error_t *
svn_subst_translate_stream (svn_stream_t *s, /* src stream */
svn_stream_t *d, /* dst stream */
@@ -541,6 +734,28 @@
const svn_subst_keywords_t *keywords,
svn_boolean_t expand)
{
+ apr_pool_t *pool = svn_pool_create (NULL);
+ svn_subst_keyhash_t *kh =
+ keywords_to_keyhash((svn_subst_keywords_t *)keywords,
+ pool);
+
+ /* call the real function */
+ svn_error_t *err = svn_subst_translate_stream2 (s, d, eol_str,
+ repair, kh, expand);
+
+ /* Always clean up after ourselves */
+ svn_pool_destroy (pool);
+ return err;
+}
+
+svn_error_t *
+svn_subst_translate_stream2 (svn_stream_t *s, /* src stream */
+ svn_stream_t *d, /* dst stream */
+ const char *eol_str,
+ svn_boolean_t repair,
+ svn_subst_keyhash_t *keywords,
+ svn_boolean_t expand)
+{
char buf[SVN_STREAM_CHUNK_SIZE + 1];
const char *p, *interesting;
apr_size_t len, readlen;
@@ -696,7 +911,6 @@
return SVN_NO_ERROR;
}
-
svn_error_t *
svn_subst_copy_and_translate (const char *src,
const char *dst,
@@ -706,6 +920,25 @@
svn_boolean_t expand,
apr_pool_t *pool)
{
+ svn_subst_keyhash_t *kh =
+ keywords_to_keyhash((svn_subst_keywords_t *)keywords, pool);
+
+ svn_error_t *rerrer =
+ svn_subst_copy_and_translate2 (src, dst, eol_str,
+ repair, kh, expand, pool);
+
+ return rerrer;
+}
+
+svn_error_t *
+svn_subst_copy_and_translate2 (const char *src,
+ const char *dst,
+ const char *eol_str,
+ svn_boolean_t repair,
+ svn_subst_keyhash_t *keywords,
+ svn_boolean_t expand,
+ apr_pool_t *pool)
+{
const char *dst_tmp = NULL;
svn_stream_t *src_stream, *dst_stream;
apr_file_t *s = NULL, *d = NULL; /* init to null important for APR */
@@ -742,8 +975,8 @@
dst_stream = svn_stream_from_aprfile (d, subpool);
/* Translate src stream into dst stream. */
- err = svn_subst_translate_stream (src_stream, dst_stream,
- eol_str, repair, keywords, expand);
+ err = svn_subst_translate_stream2 (src_stream, dst_stream,
+ eol_str, repair, keywords, expand);
if (err)
goto error;
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sun Apr 18 05:22:56 2004