diff options
Diffstat (limited to 'src/commit.c')
-rw-r--r-- | src/commit.c | 243 |
1 files changed, 206 insertions, 37 deletions
diff --git a/src/commit.c b/src/commit.c index a1a5bf7f..6b0b6619 100644 --- a/src/commit.c +++ b/src/commit.c @@ -29,14 +29,22 @@ #include "git/odb.h" #define COMMIT_PRINT(commit) {\ - char oid[41]; oid[40] = 0;\ - git_oid_fmt(oid, &commit->object.id);\ - printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\ + char oid[41]; oid[40] = 0;\ + git_oid_fmt(oid, &commit->object.id);\ + printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\ } void git_commit__free(git_commit *commit) { git_commit_list_clear(&commit->parents, 0); + + if (commit->odb_open) + git_obj_close(&commit->odb_object); + + free(commit->author); + free(commit->committer); + free(commit->message); + free(commit->message_short); free(commit); } @@ -69,7 +77,7 @@ git_commit *git_commit_parse(git_revpool *pool, const git_oid *id) if ((commit = git_commit_lookup(pool, id)) == NULL) return NULL; - if (git_commit_parse_existing(commit) < 0) + if (git_commit__parse_basic(commit) < 0) goto error_cleanup; return commit; @@ -79,30 +87,51 @@ error_cleanup: return NULL; } -int git_commit_parse_existing(git_commit *commit) +int git_commit__parse(git_commit *commit, unsigned int parse_flags, int close_db_object) { int error = 0; - git_obj commit_obj; - if (commit->parsed) - return 0; + if (!commit->odb_open) { + error = git_odb_read(&commit->odb_object, commit->object.pool->db, &commit->object.id); + if (error < 0) + return error; - error = git_odb_read(&commit_obj, commit->object.pool->db, &commit->object.id); - if (error < 0) - return error; + if (commit->odb_object.type != GIT_OBJ_COMMIT) { + git_obj_close(&commit->odb_object); + return GIT_EOBJTYPE; + } - if (commit_obj.type != GIT_OBJ_COMMIT) { - error = GIT_EOBJTYPE; - goto cleanup; + commit->odb_open = 1; } - error = git_commit__parse_buffer(commit, commit_obj.data, commit_obj.len); + error = git_commit__parse_buffer(commit, + commit->odb_object.data, commit->odb_object.len, parse_flags); + + if (close_db_object) { + git_obj_close(&commit->odb_object); + commit->odb_open = 0; + } -cleanup: - git_obj_close(&commit_obj); return error; } +int git_commit__parse_basic(git_commit *commit) +{ + int error; + + if (commit->basic_parse) + return 0; + + error = git_commit__parse(commit, + (GIT_COMMIT_TREE | GIT_COMMIT_PARENTS | GIT_COMMIT_TIME), 1); + + if (error < 0) + return error; + + commit->basic_parse = 1; + return 0; +} + git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id) { git_commit *commit = NULL; @@ -131,35 +160,67 @@ git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id) return commit; } -int git_commit__parse_time(time_t *commit_time, char *buffer, const char *buffer_end) +int git_commit__parse_person(git_commit_person *person, char **buffer_out, + const char *buffer_end, const char *header) { - if (memcmp(buffer, "author ", 7) != 0) + const size_t header_len = strlen(header); + + int i; + char *buffer = *buffer_out; + char *line_end, *name, *email; + + line_end = memchr(buffer, '\n', buffer_end - buffer); + if (!line_end) return GIT_EOBJCORRUPTED; - buffer = memchr(buffer, '\n', buffer_end - buffer); - if (!buffer || ++buffer >= buffer_end) + if (buffer + (header_len + 1) > line_end) return GIT_EOBJCORRUPTED; - if (memcmp(buffer, "committer ", 10) != 0) + if (memcmp(buffer, header, header_len) != 0) return GIT_EOBJCORRUPTED; - buffer = memchr(buffer, '>', buffer_end - buffer); - if (!buffer || ++buffer >= buffer_end) + buffer += header_len; + + + /* Parse name field */ + for (i = 0, name = person->name; + i < 64 && buffer < line_end && *buffer != '<'; + ++i) + *name++ = *buffer++; + + *(name - 1) = 0; + + while (buffer < line_end && *buffer != '<') + buffer++; + + if (++buffer >= line_end) return GIT_EOBJCORRUPTED; - *commit_time = strtol(buffer, &buffer, 10); + /* Parse email field */ + for (i = 0, email = person->email; + i < 64 && buffer < line_end && *buffer != '>'; + ++i) + *email++ = *buffer++; + + *email = 0; + + while (buffer < line_end && *buffer != '>') + buffer++; - if (*commit_time == 0) + if (++buffer >= line_end) return GIT_EOBJCORRUPTED; - buffer = memchr(buffer, '\n', buffer_end - buffer); - if (!buffer || ++buffer >= buffer_end) + person->time = strtol(buffer, &buffer, 10); + + if (person->time == 0) return GIT_EOBJCORRUPTED; - return (buffer < buffer_end) ? 0 : -1; + *buffer_out = (line_end + 1); + return 0; } -int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header) +int git_commit__parse_oid(git_oid *oid, char **buffer_out, + const char *buffer_end, const char *header) { const size_t sha_len = GIT_OID_HEXSZ; const size_t header_len = strlen(header); @@ -183,28 +244,33 @@ int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_en return 0; } -int git_commit__parse_buffer(git_commit *commit, void *data, size_t len) +int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) { char *buffer = (char *)data; const char *buffer_end = (char *)data + len; git_oid oid; - - if (commit->parsed) - return 0; + git_commit_person person; if (git_commit__parse_oid(&oid, &buffer, buffer_end, "tree ") < 0) return GIT_EOBJCORRUPTED; - commit->tree = git_tree_lookup(commit->object.pool, &oid); + if (parse_flags & GIT_COMMIT_TREE) + commit->tree = git_tree_lookup(commit->object.pool, &oid); /* * TODO: commit grafts! */ + if (parse_flags & GIT_COMMIT_PARENTS) + git_commit_list_clear(&commit->parents, 0); + while (git_commit__parse_oid(&oid, &buffer, buffer_end, "parent ") == 0) { git_commit *parent; + if ((parse_flags & GIT_COMMIT_PARENTS) == 0) + continue; + if ((parent = git_commit_lookup(commit->object.pool, &oid)) == NULL) return GIT_ENOTFOUND; @@ -216,14 +282,117 @@ int git_commit__parse_buffer(git_commit *commit, void *data, size_t len) return GIT_ENOMEM; } - if (git_commit__parse_time(&commit->commit_time, buffer, buffer_end) < 0) + if (git_commit__parse_person(&person, &buffer, buffer_end, "author ") < 0) return GIT_EOBJCORRUPTED; - commit->parsed = 1; + if (parse_flags & GIT_COMMIT_AUTHOR) { + if (commit->author) + free(commit->author); + + commit->author = git__malloc(sizeof(git_commit_person)); + memcpy(commit->author, &person, sizeof(git_commit_person)); + } + + if (git_commit__parse_person(&person, &buffer, buffer_end, "committer ") < 0) + return GIT_EOBJCORRUPTED; + + if (parse_flags & GIT_COMMIT_TIME) + commit->commit_time = person.time; + + if (parse_flags & GIT_COMMIT_COMMITTER) { + if (commit->committer) + free(commit->committer); + + commit->committer = git__malloc(sizeof(git_commit_person)); + memcpy(commit->committer, &person, sizeof(git_commit_person)); + } + + /* parse commit message */ + while (buffer <= buffer_end && *buffer == '\n') + buffer++; + + if (buffer < buffer_end) + { + if (parse_flags & GIT_COMMIT_MESSAGE) { + size_t message_len = buffer_end - buffer; + + commit->message = git__malloc(message_len + 1); + memcpy(commit->message, buffer, message_len); + commit->message[message_len] = 0; + } + + if (parse_flags & GIT_COMMIT_MESSAGE_SHORT) { + char *line_end; + size_t message_len; + + line_end = memchr(buffer, '\n', buffer_end - buffer); + message_len = line_end - buffer; + + commit->message_short = git__malloc(message_len + 1); + memcpy(commit->message_short, buffer, message_len); + commit->message_short[message_len] = 0; + } + } return 0; } +const git_tree *git_commit_tree(git_commit *commit) +{ + if (commit->tree) + return commit->tree; + + git_commit__parse(commit, GIT_COMMIT_TREE, 0); + return commit->tree; +} + +const git_commit_person *git_commit_author(git_commit *commit) +{ + if (commit->author) + return commit->author; + + git_commit__parse(commit, GIT_COMMIT_AUTHOR, 0); + return commit->author; +} + +const git_commit_person *git_commit_committer(git_commit *commit) +{ + if (commit->committer) + return commit->committer; + + git_commit__parse(commit, GIT_COMMIT_COMMITTER, 0); + return commit->committer; +} + +time_t git_commit_time(git_commit *commit) +{ + if (commit->commit_time) + return commit->commit_time; + + git_commit__parse(commit, GIT_COMMIT_TIME, 0); + return commit->commit_time; +} + +const char *git_commit_message(git_commit *commit) +{ + if (commit->message) + return commit->message; + + git_commit__parse(commit, GIT_COMMIT_MESSAGE, 0); + return commit->message; +} + +const char *git_commit_message_short(git_commit *commit) +{ + if (commit->message_short) + return commit->message_short; + + git_commit__parse(commit, GIT_COMMIT_MESSAGE_SHORT, 0); + return commit->message_short; +} + + + int git_commit_list_push_back(git_commit_list *list, git_commit *commit) { git_commit_node *node = NULL; |