summaryrefslogtreecommitdiff
path: root/src/revparse.c
diff options
context:
space:
mode:
authorBen Straub <bstraub@github.com>2012-05-30 16:52:11 -0700
committerBen Straub <bstraub@github.com>2012-05-30 16:52:11 -0700
commit244d2f6b80161978cce5bacc3ac6e663b530bb65 (patch)
tree65cdc085f504451ebc6ebf536b01d95326751e82 /src/revparse.c
parentdd9e4abc1ba1701efac0c3af3b1ceede2bd561a4 (diff)
downloadlibgit2-244d2f6b80161978cce5bacc3ac6e663b530bb65.tar.gz
Rev-parse: add "tag:README" syntax.
Diffstat (limited to 'src/revparse.c')
-rw-r--r--src/revparse.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/src/revparse.c b/src/revparse.c
index 3615ac519..1e78d7623 100644
--- a/src/revparse.c
+++ b/src/revparse.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "buffer.h"
#include "date.h"
+#include "tree.h"
#include "git2.h"
@@ -19,6 +20,7 @@ typedef enum {
REVPARSE_STATE_INIT,
REVPARSE_STATE_CARET,
REVPARSE_STATE_LINEAR,
+ REVPARSE_STATE_COLON,
REVPARSE_STATE_DONE,
} revparse_state;
@@ -535,6 +537,45 @@ static int handle_linear_syntax(git_object **out, git_object *obj, const char *m
return 0;
}
+static const git_tree_entry* git_tree_entry_bypath(git_tree *tree, git_repository *repo, const char *path)
+{
+ char *str = git__strdup(path);
+ char *tok;
+ git_tree *tree2 = tree;
+ const git_tree_entry *entry;
+
+ while ((tok = git__strtok(&str, "/\\")) != NULL) {
+ entry = git_tree_entry_byname(tree2, tok);
+ if (tree2 != tree) git_tree_free(tree2);
+ if (entry_is_tree(entry)) {
+ if (git_tree_lookup(&tree2, repo, &entry->oid) < 0) {
+ return NULL;
+ }
+ }
+ }
+
+ return entry;
+}
+
+static int handle_colon_syntax(git_object **out,
+ git_repository *repo,
+ git_object *obj,
+ const char *path)
+{
+ git_tree *tree;
+ const git_tree_entry *entry;
+
+ /* Dereference until we reach a tree. */
+ if (dereference_to_type(&obj, obj, GIT_OBJ_TREE) < 0) {
+ return GIT_ERROR;
+ }
+ tree = (git_tree*)obj;
+
+ /* Find the blob at the given path. */
+ entry = git_tree_entry_bypath(tree, repo, path);
+ return git_tree_entry_2object(out, repo, entry);
+}
+
int git_revparse_single(git_object **out, git_repository *repo, const char *spec)
{
revparse_state current_state = REVPARSE_STATE_INIT, next_state = REVPARSE_STATE_INIT;
@@ -545,6 +586,13 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec
assert(out && repo && spec);
+ if (spec[0] == ':') {
+ /* Either a global grep (":/foo") or a merge-stage path lookup (":2:Makefile").
+ Neither of these are handled just yet. */
+ giterr_set(GITERR_INVALID, "Unimplemented");
+ return GIT_ERROR;
+ }
+
while (current_state != REVPARSE_STATE_DONE) {
switch (current_state) {
case REVPARSE_STATE_INIT:
@@ -561,6 +609,8 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec
next_state = REVPARSE_STATE_CARET;
} else if (*spec_cur == '~') {
next_state = REVPARSE_STATE_LINEAR;
+ } else if (*spec_cur == ':') {
+ next_state = REVPARSE_STATE_COLON;
} else {
git_buf_putc(&specbuffer, *spec_cur);
}
@@ -617,6 +667,16 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec
spec_cur++;
break;
+ case REVPARSE_STATE_COLON:
+ if (*spec_cur) {
+ git_buf_putc(&stepbuffer, *spec_cur);
+ } else {
+ retcode = handle_colon_syntax(out, repo, cur_obj, git_buf_cstr(&stepbuffer));
+ next_state = REVPARSE_STATE_DONE;
+ }
+ spec_cur++;
+ break;
+
case REVPARSE_STATE_DONE:
if (cur_obj && *out != cur_obj) git_object_free(cur_obj);
if (next_obj && *out != next_obj) git_object_free(next_obj);