static int parse_patch_hunks( git_patch_parsed *patch, git_patch_parse_ctx *ctx) { git_patch_hunk *hunk; int error = 0; while (git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -")) { hunk = git_array_alloc(patch->base.hunks); GITERR_CHECK_ALLOC(hunk); memset(hunk, 0, sizeof(git_patch_hunk)); hunk->line_start = git_array_size(patch->base.lines); hunk->line_count = 0; if ((error = parse_hunk_header(hunk, ctx)) < 0 || (error = parse_hunk_body(patch, hunk, ctx)) < 0) goto done; } patch->base.delta->flags |= GIT_DIFF_FLAG_NOT_BINARY; done: return error; }
static int mark_uninteresting(git_revwalk *walk, git_commit_list_node *commit) { int error; unsigned short i; git_array_t(git_commit_list_node *) pending = GIT_ARRAY_INIT; git_commit_list_node **tmp; assert(commit); do { commit->uninteresting = 1; if ((error = git_commit_list_parse(walk, commit)) < 0) return error; for (i = 0; i < commit->out_degree; ++i) if (!commit->parents[i]->uninteresting) { git_commit_list_node **node = git_array_alloc(pending); GITERR_CHECK_ALLOC(node); *node = commit->parents[i]; } tmp = git_array_pop(pending); commit = tmp ? *tmp : NULL; } while (commit != NULL); git_array_clear(pending); return 0; }
static int rebase_open_merge(git_rebase *rebase) { git_buf state_path = GIT_BUF_INIT, buf = GIT_BUF_INIT, cmt = GIT_BUF_INIT; git_oid current_id = {{0}}; git_rebase_operation *operation; size_t i, msgnum = 0, end; int error; if ((error = git_buf_puts(&state_path, rebase->state_path)) < 0) goto done; /* Read 'msgnum' if it exists (otherwise, let msgnum = 0) */ if ((error = rebase_readint(&msgnum, &buf, &state_path, MSGNUM_FILE)) < 0 && error != GIT_ENOTFOUND) goto done; if (msgnum) { rebase->started = 1; rebase->current = msgnum - 1; } /* Read 'end' */ if ((error = rebase_readint(&end, &buf, &state_path, END_FILE)) < 0) goto done; /* Read 'current' if it exists */ if ((error = rebase_readoid(¤t_id, &buf, &state_path, CURRENT_FILE)) < 0 && error != GIT_ENOTFOUND) goto done; /* Read cmt.* */ git_array_init_to_size(rebase->operations, end); GITERR_CHECK_ARRAY(rebase->operations); for (i = 0; i < end; i++) { operation = git_array_alloc(rebase->operations); GITERR_CHECK_ALLOC(operation); git_buf_clear(&cmt); if ((error = git_buf_printf(&cmt, "cmt.%" PRIuZ, (i+1))) < 0 || (error = rebase_readoid((git_oid *)&operation->id, &buf, &state_path, cmt.ptr)) < 0) goto done; } /* Read 'onto_name' */ if ((error = rebase_readfile(&buf, &state_path, ONTO_NAME_FILE)) < 0) goto done; rebase->onto_name = git_buf_detach(&buf); done: git_buf_free(&cmt); git_buf_free(&state_path); git_buf_free(&buf); return error; }
static int rebase_init_operations( git_rebase *rebase, git_repository *repo, const git_annotated_commit *branch, const git_annotated_commit *upstream, const git_annotated_commit *onto) { git_revwalk *revwalk = NULL; git_commit *commit; git_oid id; bool merge; git_rebase_operation *operation; int error; if (!upstream) upstream = onto; if ((error = git_revwalk_new(&revwalk, rebase->repo)) < 0 || (error = git_revwalk_push(revwalk, git_annotated_commit_id(branch))) < 0 || (error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0) goto done; git_revwalk_sorting(revwalk, GIT_SORT_REVERSE | GIT_SORT_TIME); while ((error = git_revwalk_next(&id, revwalk)) == 0) { if ((error = git_commit_lookup(&commit, repo, &id)) < 0) goto done; merge = (git_commit_parentcount(commit) > 1); git_commit_free(commit); if (merge) continue; operation = git_array_alloc(rebase->operations); operation->type = GIT_REBASE_OPERATION_PICK; git_oid_cpy((git_oid *)&operation->id, &id); } error = 0; done: git_revwalk_free(revwalk); return error; }
static int diff_driver_add_patterns( git_diff_driver *drv, const char *regex_str, int regex_flags) { int error = 0; const char *scan, *end; git_diff_driver_pattern *pat = NULL; git_buf buf = GIT_BUF_INIT; for (scan = regex_str; scan; scan = end) { /* get pattern to fill in */ if ((pat = git_array_alloc(drv->fn_patterns)) == NULL) { error = -1; break; } pat->flags = regex_flags; if (*scan == '!') { pat->flags |= REG_NEGATE; ++scan; } if ((end = strchr(scan, '\n')) != NULL) { error = git_buf_set(&buf, scan, end - scan); end++; } else { error = git_buf_sets(&buf, scan); } if (error < 0) break; if ((error = regcomp(&pat->re, buf.ptr, regex_flags)) < 0) { /* if regex fails to compile, warn? fail? */ error = giterr_set_regex(&pat->re, error); regfree(&pat->re); break; } } if (error && pat != NULL) (void)git_array_pop(drv->fn_patterns); /* release last item */ git_buf_free(&buf); return error; }
static git_rebase_operation *rebase_operation_alloc( git_rebase *rebase, git_rebase_operation_t type, git_oid *id, const char *exec) { git_rebase_operation *operation; assert((type == GIT_REBASE_OPERATION_EXEC) == !id); assert((type == GIT_REBASE_OPERATION_EXEC) == !!exec); if ((operation = git_array_alloc(rebase->operations)) == NULL) return NULL; operation->type = type; git_oid_cpy((git_oid *)&operation->id, id); operation->exec = exec; return operation; }
static int validate_tree_and_parents(git_array_oid_t *parents, git_repository *repo, const git_oid *tree, git_commit_parent_callback parent_cb, void *parent_payload, const git_oid *current_id, bool validate) { size_t i; int error; git_oid *parent_cpy; const git_oid *parent; if (validate && !git_object__is_valid(repo, tree, GIT_OBJECT_TREE)) return -1; i = 0; while ((parent = parent_cb(i, parent_payload)) != NULL) { if (validate && !git_object__is_valid(repo, parent, GIT_OBJECT_COMMIT)) { error = -1; goto on_error; } parent_cpy = git_array_alloc(*parents); GITERR_CHECK_ALLOC(parent_cpy); git_oid_cpy(parent_cpy, parent); i++; } if (current_id && (parents->size == 0 || git_oid_cmp(current_id, git_array_get(*parents, 0)))) { giterr_set(GITERR_OBJECT, "failed to create commit: current tip is not the first parent"); error = GIT_EMODIFIED; goto on_error; } return 0; on_error: git_array_clear(*parents); return error; }
static int parse_hunk_body( git_patch_parsed *patch, git_patch_hunk *hunk, git_patch_parse_ctx *ctx) { git_diff_line *line; int error = 0; int oldlines = hunk->hunk.old_lines; int newlines = hunk->hunk.new_lines; for (; ctx->parse_ctx.remain_len > 1 && (oldlines || newlines) && !git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -"); git_parse_advance_line(&ctx->parse_ctx)) { char c; int origin; int prefix = 1; if (ctx->parse_ctx.line_len == 0 || ctx->parse_ctx.line[ctx->parse_ctx.line_len - 1] != '\n') { error = git_parse_err("invalid patch instruction at line %"PRIuZ, ctx->parse_ctx.line_num); goto done; } git_parse_peek(&c, &ctx->parse_ctx, 0); switch (c) { case '\n': prefix = 0; /* fall through */ case ' ': origin = GIT_DIFF_LINE_CONTEXT; oldlines--; newlines--; break; case '-': origin = GIT_DIFF_LINE_DELETION; oldlines--; break; case '+': origin = GIT_DIFF_LINE_ADDITION; newlines--; break; default: error = git_parse_err("invalid patch hunk at line %"PRIuZ, ctx->parse_ctx.line_num); goto done; } line = git_array_alloc(patch->base.lines); GITERR_CHECK_ALLOC(line); memset(line, 0x0, sizeof(git_diff_line)); line->content = ctx->parse_ctx.line + prefix; line->content_len = ctx->parse_ctx.line_len - prefix; line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len; line->origin = origin; hunk->line_count++; } if (oldlines || newlines) { error = git_parse_err( "invalid patch hunk, expected %d old lines and %d new lines", hunk->hunk.old_lines, hunk->hunk.new_lines); goto done; } /* Handle "\ No newline at end of file". Only expect the leading * backslash, though, because the rest of the string could be * localized. Because `diff` optimizes for the case where you * want to apply the patch by hand. */ if (git_parse_ctx_contains_s(&ctx->parse_ctx, "\\ ") && git_array_size(patch->base.lines) > 0) { line = git_array_get(patch->base.lines, git_array_size(patch->base.lines) - 1); if (line->content_len < 1) { error = git_parse_err("cannot trim trailing newline of empty line"); goto done; } line->content_len--; git_parse_advance_line(&ctx->parse_ctx); } done: return error; }
int git_commit__parse_raw(void *_commit, const char *data, size_t size) { git_commit *commit = _commit; const char *buffer_start = data, *buffer; const char *buffer_end = buffer_start + size; git_oid parent_id; size_t header_len; git_signature dummy_sig; buffer = buffer_start; /* Allocate for one, which will allow not to realloc 90% of the time */ git_array_init_to_size(commit->parent_ids, 1); GITERR_CHECK_ARRAY(commit->parent_ids); /* The tree is always the first field */ if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0) goto bad_buffer; /* * TODO: commit grafts! */ while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { git_oid *new_id = git_array_alloc(commit->parent_ids); GITERR_CHECK_ALLOC(new_id); git_oid_cpy(new_id, &parent_id); } commit->author = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->author); if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0) return -1; /* Some tools create multiple author fields, ignore the extra ones */ while (!git__prefixncmp(buffer, buffer_end - buffer, "author ")) { if (git_signature__parse(&dummy_sig, &buffer, buffer_end, "author ", '\n') < 0) return -1; git__free(dummy_sig.name); git__free(dummy_sig.email); } /* Always parse the committer; we need the commit time */ commit->committer = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->committer); if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0) return -1; /* Parse add'l header entries */ while (buffer < buffer_end) { const char *eoln = buffer; if (buffer[-1] == '\n' && buffer[0] == '\n') break; while (eoln < buffer_end && *eoln != '\n') ++eoln; if (git__prefixncmp(buffer, buffer_end - buffer, "encoding ") == 0) { buffer += strlen("encoding "); commit->message_encoding = git__strndup(buffer, eoln - buffer); GITERR_CHECK_ALLOC(commit->message_encoding); } if (eoln < buffer_end && *eoln == '\n') ++eoln; buffer = eoln; } header_len = buffer - buffer_start; commit->raw_header = git__strndup(buffer_start, header_len); GITERR_CHECK_ALLOC(commit->raw_header); /* point "buffer" to data after header, +1 for the final LF */ buffer = buffer_start + header_len + 1; /* extract commit message */ if (buffer <= buffer_end) commit->raw_message = git__strndup(buffer, buffer_end - buffer); else commit->raw_message = git__strdup(""); GITERR_CHECK_ALLOC(commit->raw_message); return 0; bad_buffer: giterr_set(GITERR_OBJECT, "failed to parse bad commit object"); return -1; }