diff options
Diffstat (limited to 'src/commit.c')
-rw-r--r-- | src/commit.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/commit.c b/src/commit.c index 710a14e92..e589dde54 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; +} |