Commit 92cb6aa929f60eaea66359c8e3258de821a0a965

Carlos Martín Nieto 2011-06-23T15:41:29

Add git_refspec_transform Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>

diff --git a/include/git2/refspec.h b/include/git2/refspec.h
index 8523d5a..0cbe42f 100644
--- a/include/git2/refspec.h
+++ b/include/git2/refspec.h
@@ -29,4 +29,14 @@ const char *git_refspec_dst(const git_refspec *refspec);
  */
 int git_refspec_src_match(const git_refspec *refspec, const char *refname);
 
+/**
+ * Transform a reference to its target following the refspec's rules
+ *
+ * @param out where to store the target name
+ * @param in the source reference
+ * @param spec the refspec
+ * @param len the length of the out buffer
+ * @preturn GIT_SUCCESS, GIT_ESHORTBUFFER or another error
+ */
+int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec,  const char *name);
 #endif
diff --git a/src/refspec.c b/src/refspec.c
index 38cbb05..8500e07 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -23,6 +23,8 @@
  * Boston, MA 02110-1301, USA.
  */
 
+#include "git2/errors.h"
+
 #include "common.h"
 #include "refspec.h"
 #include "util.h"
@@ -70,3 +72,37 @@ int git_refspec_src_match(const git_refspec *refspec, const char *refname)
 {
 	return git__fnmatch(refspec->src, refname, 0);
 }
+
+int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec,  const char *name)
+{
+	size_t baselen, namelen;
+
+	baselen = strlen(spec->dst);
+	if (outlen <= baselen)
+		return git__throw(GIT_EINVALIDREFNAME, "Reference name too long");
+
+	/*
+	 * No '*' at the end means that it's mapped to one specific local
+	 * branch, so no actual transformation is needed.
+	 */
+	if (spec->dst[baselen - 1] != '*') {
+		memcpy(out, spec->dst, baselen + 1); /* include '\0' */
+		return GIT_SUCCESS;
+	}
+
+	/* There's a '*' at the end, so remove its length */
+	baselen--;
+
+	/* skip the prefix, -1 is for the '*' */
+	name += strlen(spec->src) - 1;
+
+	namelen = strlen(name);
+
+	if (outlen <= baselen + namelen)
+		return git__throw(GIT_EINVALIDREFNAME, "Reference name too long");
+
+	memcpy(out, spec->dst, baselen);
+	memcpy(out + baselen, name, namelen + 1);
+
+	return GIT_SUCCESS;
+}