summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commit.c118
-rw-r--r--src/commit.h9
-rw-r--r--src/git/commit.h4
3 files changed, 129 insertions, 2 deletions
diff --git a/src/commit.c b/src/commit.c
index 710a14e9..e589dde5 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -23,10 +23,128 @@
* Boston, MA 02110-1301, USA.
*/
+#include <time.h>
+
#include "common.h"
#include "commit.h"
+#include "revwalk.h"
+#include "git/odb.h"
const git_oid *git_commit_id(git_commit *c)
{
return &c->id;
}
+
+git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id)
+{
+ git_obj commit_obj;
+ git_commit *commit = NULL;
+
+ /*
+ * TODO: check if the commit is already cached in the
+ * revpool instead of loading it from the odb
+ */
+
+ if (git_odb_read(&commit_obj, pool->db, id) < 0)
+ return NULL;
+
+ if (commit_obj.type != GIT_OBJ_COMMIT)
+ goto error_cleanup;
+
+ commit = git__malloc(sizeof(git_commit));
+ memset(commit, 0x0, sizeof(git_commit));
+
+ git_oid_cpy(&commit->id, id);
+ commit->pool = pool;
+
+ if (git_commit__parse_buffer(commit, commit_obj.data, commit_obj.len) < 0)
+ goto error_cleanup;
+
+ return commit;
+
+error_cleanup:
+ git_obj_close(&commit_obj);
+ free(commit);
+
+ return NULL;
+}
+
+int git_commit__parse_time(time_t *commit_time, char *buffer, const char *buffer_end)
+{
+ if (memcmp(buffer, "author ", 7) != 0)
+ return -1;
+
+ buffer = memchr(buffer, '\n', buffer_end - buffer);
+ if (buffer == 0 || buffer >= buffer_end)
+ return -1;
+
+ if (memcmp(buffer, "committer ", 10) != 0)
+ return -1;
+
+ buffer = memchr(buffer, '\n', buffer_end - buffer);
+ if (buffer == 0 || buffer >= buffer_end)
+ return -1;
+
+ *commit_time = strtol(buffer, &buffer, 10);
+
+ return (buffer < buffer_end) ? 0 : -1;
+}
+
+int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header)
+{
+ size_t sha_len = GIT_OID_HEXSZ;
+ size_t header_len = strlen(header);
+
+ char *buffer = *buffer_out;
+
+ if (buffer + (header_len + sha_len + 1) > buffer_end)
+ return -1;
+
+ if (memcmp(buffer, header, header_len) != 0)
+ return -1;
+
+ if (buffer[header_len + sha_len] != '\n')
+ return -1;
+
+ if (git_oid_mkstr(oid, buffer + header_len) < 0)
+ return -1;
+
+ *buffer_out = buffer + (header_len + sha_len + 1);
+
+ return 0;
+}
+
+int git_commit__parse_buffer(git_commit *commit, void *data, size_t len)
+{
+ char *buffer = (char *)data;
+ const char *buffer_end = (char *)data + len;
+
+ git_oid oid;
+
+ if (commit->parsed)
+ return 0;
+
+ if (git_commit__parse_oid(&oid, &buffer, buffer_end, "tree ") < 0)
+ return -1;
+
+ /*
+ * TODO: load tree into commit object
+ * TODO: commit grafts!
+ */
+
+ while (git_commit__parse_oid(&oid, &buffer, buffer_end, "parent ") == 0) {
+ git_commit *parent;
+
+ if ((parent = git_commit_lookup(commit->pool, &oid)) == NULL)
+ return -1;
+
+ // TODO: push the new commit into the revpool
+ }
+
+ if (git_commit__parse_time(&commit->commit_time, buffer, buffer_end) < 0)
+ return -1;
+
+ commit->parsed = 1;
+
+ return 0;
+}
diff --git a/src/commit.h b/src/commit.h
index 05504cd3..1cdb9a4f 100644
--- a/src/commit.h
+++ b/src/commit.h
@@ -5,11 +5,20 @@
#include <time.h>
+#define GIT_COMMIT_SEEN (1 << 0)
+#define GIT_COMMIT_HIDE (1 << 1)
+#define GIT_COMMIT_DELAY (1 << 2)
+
struct git_commit {
git_oid id;
time_t commit_time;
+ git_revpool *pool;
unsigned parsed:1,
flags:26;
};
+int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header);
+int git_commit__parse_buffer(git_commit *commit, void *data, size_t len);
+int git_commit__parse_time(time_t *commit_time, char *buffer, const char *buffer_end);
+
#endif
diff --git a/src/git/commit.h b/src/git/commit.h
index 010f258a..ea59a210 100644
--- a/src/git/commit.h
+++ b/src/git/commit.h
@@ -17,7 +17,7 @@ GIT_BEGIN_DECL
typedef struct git_commit git_commit;
/**
- * Parse (or lookup) a commit from a revision pool.
+ * Lookup a commit from a revision pool, and parse it if needed.
* @param pool the pool to use when parsing/caching the commit.
* @param id identity of the commit to locate. If the object is
* an annotated tag it will be peeled back to the commit.
@@ -25,7 +25,7 @@ typedef struct git_commit git_commit;
* pool's git_odb, or if the commit is present but is
* too malformed to be parsed successfully.
*/
-GIT_EXTERN(git_commit *) git_commit_parse(git_revpool *pool, const git_oid *id);
+GIT_EXTERN(git_commit *) git_commit_lookup(git_revpool *pool, const git_oid *id);
/**
* Get the id of a commit.