static int notes_copy_from_stdin(int force, const char *rewrite_cmd) { struct strbuf buf = STRBUF_INIT; struct notes_rewrite_cfg *c = NULL; struct notes_tree *t = NULL; int ret = 0; const char *msg = "Notes added by 'git notes copy'"; if (rewrite_cmd) { c = init_copy_notes_for_rewrite(rewrite_cmd); if (!c) return 0; } else { init_notes(NULL, NULL, NULL, NOTES_INIT_WRITABLE); t = &default_notes_tree; } while (strbuf_getline_lf(&buf, stdin) != EOF) { struct object_id from_obj, to_obj; struct strbuf **split; int err; split = strbuf_split(&buf, ' '); if (!split[0] || !split[1]) die(_("malformed input line: '%s'."), buf.buf); strbuf_rtrim(split[0]); strbuf_rtrim(split[1]); if (get_oid(split[0]->buf, &from_obj)) die(_("failed to resolve '%s' as a valid ref."), split[0]->buf); if (get_oid(split[1]->buf, &to_obj)) die(_("failed to resolve '%s' as a valid ref."), split[1]->buf); if (rewrite_cmd) err = copy_note_for_rewrite(c, &from_obj, &to_obj); else err = copy_note(t, &from_obj, &to_obj, force, combine_notes_overwrite); if (err) { error(_("failed to copy notes from '%s' to '%s'"), split[0]->buf, split[1]->buf); ret = 1; } strbuf_list_free(split); } if (!rewrite_cmd) { commit_notes(t, msg); free_notes(t); } else { finish_copy_notes_for_rewrite(c, msg); } strbuf_release(&buf); return ret; }
int notes_copy_from_stdin(int force, const char *rewrite_cmd) { struct strbuf buf = STRBUF_INIT; struct notes_rewrite_cfg *c = NULL; struct notes_tree *t = NULL; int ret = 0; if (rewrite_cmd) { c = init_copy_notes_for_rewrite(rewrite_cmd); if (!c) return 0; } else { init_notes(NULL, NULL, NULL, 0); t = &default_notes_tree; } while (strbuf_getline(&buf, stdin, '\n') != EOF) { unsigned char from_obj[20], to_obj[20]; struct strbuf **split; int err; split = strbuf_split(&buf, ' '); if (!split[0] || !split[1]) die("Malformed input line: '%s'.", buf.buf); strbuf_rtrim(split[0]); strbuf_rtrim(split[1]); if (get_sha1(split[0]->buf, from_obj)) die("Failed to resolve '%s' as a valid ref.", split[0]->buf); if (get_sha1(split[1]->buf, to_obj)) die("Failed to resolve '%s' as a valid ref.", split[1]->buf); if (rewrite_cmd) err = copy_note_for_rewrite(c, from_obj, to_obj); else err = copy_note(t, from_obj, to_obj, force, combine_notes_overwrite); if (err) { error("Failed to copy notes from '%s' to '%s'", split[0]->buf, split[1]->buf); ret = 1; } strbuf_list_free(split); } if (!rewrite_cmd) { commit_notes(t, "Notes added by 'git notes copy'"); free_notes(t); } else { finish_copy_notes_for_rewrite(c); } return ret; }
static int bisect_reset(const char *commit) { struct strbuf branch = STRBUF_INIT; if (!commit) { if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) { printf(_("We are not bisecting.\n")); return 0; } strbuf_rtrim(&branch); } else { struct object_id oid; if (get_oid_commit(commit, &oid)) return error(_("'%s' is not a valid commit"), commit); strbuf_addstr(&branch, commit); } if (!file_exists(git_path_bisect_head())) { struct argv_array argv = ARGV_ARRAY_INIT; argv_array_pushl(&argv, "checkout", branch.buf, "--", NULL); if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) { strbuf_release(&branch); argv_array_clear(&argv); return error(_("could not check out original" " HEAD '%s'. Try 'git bisect" "reset <commit>'."), branch.buf); } argv_array_clear(&argv); } strbuf_release(&branch); return bisect_clean_state(); }
static void fetch_symref(const char *path, char **symref, struct object_id *oid) { char *url = xstrfmt("%s%s", repo->url, path); struct strbuf buffer = STRBUF_INIT; const char *name; if (http_get_strbuf(url, &buffer, NULL) != HTTP_OK) die("Couldn't get %s for remote symref\n%s", url, curl_errorstr); free(url); FREE_AND_NULL(*symref); oidclr(oid); if (buffer.len == 0) return; /* Cut off trailing newline. */ strbuf_rtrim(&buffer); /* If it's a symref, set the refname; otherwise try for a sha1 */ if (skip_prefix(buffer.buf, "ref: ", &name)) { *symref = xmemdupz(name, buffer.len - (name - buffer.buf)); } else { get_oid_hex(buffer.buf, oid); } strbuf_release(&buffer); }
static struct worktree *get_linked_worktree(const char *id) { struct worktree *worktree = NULL; struct strbuf path = STRBUF_INIT; struct strbuf worktree_path = STRBUF_INIT; if (!id) die("Missing linked worktree name"); strbuf_git_common_path(&path, the_repository, "worktrees/%s/gitdir", id); if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0) /* invalid gitdir file */ goto done; strbuf_rtrim(&worktree_path); if (!strbuf_strip_suffix(&worktree_path, "/.git")) { strbuf_reset(&worktree_path); strbuf_add_absolute_path(&worktree_path, "."); strbuf_strip_suffix(&worktree_path, "/."); } strbuf_reset(&path); strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id); worktree = xcalloc(1, sizeof(*worktree)); worktree->path = strbuf_detach(&worktree_path, NULL); worktree->id = xstrdup(id); add_head_info(worktree); done: strbuf_release(&path); strbuf_release(&worktree_path); return worktree; }
static int parse_bundle_header(int fd, struct bundle_header *header, const char *report_path) { struct strbuf buf = STRBUF_INIT; int status = 0; /* The bundle header begins with the signature */ if (strbuf_getwholeline_fd(&buf, fd, '\n') || strcmp(buf.buf, bundle_signature)) { if (report_path) error("'%s' does not look like a v2 bundle file", report_path); status = -1; goto abort; } /* The bundle header ends with an empty line */ while (!strbuf_getwholeline_fd(&buf, fd, '\n') && buf.len && buf.buf[0] != '\n') { unsigned char sha1[20]; int is_prereq = 0; if (*buf.buf == '-') { is_prereq = 1; strbuf_remove(&buf, 0, 1); } strbuf_rtrim(&buf); /* * Tip lines have object name, SP, and refname. * Prerequisites have object name that is optionally * followed by SP and subject line. */ if (get_sha1_hex(buf.buf, sha1) || (40 <= buf.len && !isspace(buf.buf[40])) || (!is_prereq && buf.len <= 40)) { if (report_path) error("unrecognized header: %s%s (%d)", (is_prereq ? "-" : ""), buf.buf, (int)buf.len); status = -1; break; } else { if (is_prereq) add_to_ref_list(sha1, "", &header->prerequisites); else add_to_ref_list(sha1, buf.buf + 41, &header->references); } } abort: if (status) { close(fd); fd = -1; } strbuf_release(&buf); return fd; }
static int read_one_header_line(struct strbuf *line, FILE *in) { struct strbuf continuation = STRBUF_INIT; /* Get the first part of the line. */ if (strbuf_getline_lf(line, in)) return 0; /* * Is it an empty line or not a valid rfc2822 header? * If so, stop here, and return false ("not a header") */ strbuf_rtrim(line); if (!line->len || !is_rfc2822_header(line)) { /* Re-add the newline */ strbuf_addch(line, '\n'); return 0; } /* * Now we need to eat all the continuation lines.. * Yuck, 2822 header "folding" */ for (;;) { int peek; peek = fgetc(in); if (peek == EOF) break; ungetc(peek, in); if (peek != ' ' && peek != '\t') break; if (strbuf_getline_lf(&continuation, in)) break; continuation.buf[0] = ' '; strbuf_rtrim(&continuation); strbuf_addbuf(line, &continuation); } strbuf_release(&continuation); return 1; }
static BOOL build_branch_menu(struct git_data *data, const struct menu_item *item, void *platform) { void *submenu; int status; char *wd = wd_from_path(data->name, NULL); struct strbuf output; struct strbuf **lines, **it; strbuf_init(&output, 0); status = exec_program(wd, &output, NULL, WAITMODE, "git", "branch", NULL); free(wd); if (status) return FALSE; submenu = start_submenu(data, item, platform); lines = strbuf_split(&output, '\n'); for (it = lines; *it; it++) { struct menu_item item = { MENU_ITEM_CLEANUP, 0, NULL, NULL, NULL, menu_branch }; strbuf_rtrim(*it); item.string = strdup((*it)->buf + 2); item.helptext = strdup((*it)->buf + 2); item.flags = '*' == (*it)->buf[0] ? MI_CHECKED | MI_DISABLED : 0; if (build_item(data, &item, submenu)) append_active_menu(&item); else /* * if the platform failed to create an item * there is no point to try other items */ break; } end_submenu(platform, submenu); /* technically, there is nothing to track for the menu engine */ return FALSE; }
static char *find_linked_symref(const char *symref, const char *branch, const char *id) { struct strbuf sb = STRBUF_INIT; struct strbuf path = STRBUF_INIT; struct strbuf gitdir = STRBUF_INIT; char *existing = NULL; /* * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside * $GIT_DIR so resolve_ref_unsafe() won't work (it uses * git_path). Parse the ref ourselves. */ if (id) strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref); else strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref); if (!strbuf_readlink(&sb, path.buf, 0)) { if (!starts_with(sb.buf, "refs/") || check_refname_format(sb.buf, 0)) goto done; } else if (strbuf_read_file(&sb, path.buf, 0) >= 0 && starts_with(sb.buf, "ref:")) { strbuf_remove(&sb, 0, strlen("ref:")); strbuf_trim(&sb); } else goto done; if (strcmp(sb.buf, branch)) goto done; if (id) { strbuf_reset(&path); strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id); if (strbuf_read_file(&gitdir, path.buf, 0) <= 0) goto done; strbuf_rtrim(&gitdir); } else strbuf_addstr(&gitdir, get_git_common_dir()); strbuf_strip_suffix(&gitdir, ".git"); existing = strbuf_detach(&gitdir, NULL); done: strbuf_release(&path); strbuf_release(&sb); strbuf_release(&gitdir); return existing; }
static struct worktree *get_linked_worktree(const char *id) { struct worktree *worktree = NULL; struct strbuf path = STRBUF_INIT; struct strbuf worktree_path = STRBUF_INIT; struct strbuf head_ref = STRBUF_INIT; int is_detached = 0; if (!id) die("Missing linked worktree name"); strbuf_git_common_path(&path, "worktrees/%s/gitdir", id); if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0) /* invalid gitdir file */ goto done; strbuf_rtrim(&worktree_path); if (!strbuf_strip_suffix(&worktree_path, "/.git")) { strbuf_reset(&worktree_path); strbuf_add_absolute_path(&worktree_path, "."); strbuf_strip_suffix(&worktree_path, "/."); } strbuf_reset(&path); strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id); if (parse_ref(path.buf, &head_ref, &is_detached) < 0) goto done; worktree = xmalloc(sizeof(struct worktree)); worktree->path = strbuf_detach(&worktree_path, NULL); worktree->id = xstrdup(id); worktree->is_bare = 0; worktree->head_ref = NULL; worktree->is_detached = is_detached; worktree->is_current = 0; add_head_info(&head_ref, worktree); worktree->lock_reason = NULL; worktree->lock_reason_valid = 0; done: strbuf_release(&path); strbuf_release(&worktree_path); strbuf_release(&head_ref); return worktree; }
static int remove_cmd(int argc, const char **argv, const char *prefix) { unsigned flag = 0; int from_stdin = 0; struct option options[] = { OPT_BIT(0, "ignore-missing", &flag, N_("attempt to remove non-existent note is not an error"), IGNORE_MISSING), OPT_BOOL(0, "stdin", &from_stdin, N_("read object names from the standard input")), OPT_END() }; struct notes_tree *t; int retval = 0; argc = parse_options(argc, argv, prefix, options, git_notes_remove_usage, 0); t = init_notes_check("remove"); if (!argc && !from_stdin) { retval = remove_one_note(t, "HEAD", flag); } else { while (*argv) { retval |= remove_one_note(t, *argv, flag); argv++; } } if (from_stdin) { struct strbuf sb = STRBUF_INIT; while (strbuf_getwholeline(&sb, stdin, '\n') != EOF) { strbuf_rtrim(&sb); retval |= remove_one_note(t, sb.buf, flag); } strbuf_release(&sb); } if (!retval) commit_notes(t, "Notes removed by 'git notes remove'"); free_notes(t); return retval; }
void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, struct strbuf *sb, const struct pretty_print_context *context) { unsigned long beginning_of_body; int indent = 4; const char *msg = commit->buffer; char *reencoded; const char *encoding; int need_8bit_cte = context->need_8bit_cte; if (fmt == CMIT_FMT_USERFORMAT) { format_commit_message(commit, user_format, sb, context); return; } reencoded = reencode_commit_message(commit, &encoding); if (reencoded) { msg = reencoded; } if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) indent = 0; /* * We need to check and emit Content-type: to mark it * as 8-bit if we haven't done so. */ if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) { int i, ch, in_body; for (in_body = i = 0; (ch = msg[i]); i++) { if (!in_body) { /* author could be non 7-bit ASCII but * the log may be so; skip over the * header part first. */ if (ch == '\n' && msg[i+1] == '\n') in_body = 1; } else if (non_ascii(ch)) { need_8bit_cte = 1; break; } } } pp_header(fmt, context->abbrev, context->date_mode, encoding, commit, &msg, sb); if (fmt != CMIT_FMT_ONELINE && !context->subject) { strbuf_addch(sb, '\n'); } /* Skip excess blank lines at the beginning of body, if any... */ msg = skip_empty_lines(msg); /* These formats treat the title line specially. */ if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) pp_title_line(fmt, &msg, sb, context->subject, context->after_subject, encoding, need_8bit_cte); beginning_of_body = sb->len; if (fmt != CMIT_FMT_ONELINE) pp_remainder(fmt, &msg, sb, indent); strbuf_rtrim(sb); /* Make sure there is an EOLN for the non-oneline case */ if (fmt != CMIT_FMT_ONELINE) strbuf_addch(sb, '\n'); /* * The caller may append additional body text in e-mail * format. Make sure we did not strip the blank line * between the header and the body. */ if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); if (context->show_notes) format_display_notes(commit->object.sha1, sb, encoding, NOTES_SHOW_HEADER | NOTES_INDENT); free(reencoded); }
void strbuf_trim(struct strbuf *sb) { strbuf_rtrim(sb); strbuf_ltrim(sb); }
void pretty_print_commit(struct pretty_print_context *pp, const struct commit *commit, struct strbuf *sb) { unsigned long beginning_of_body; int indent = 4; const char *msg; const char *reencoded; const char *encoding; int need_8bit_cte = pp->need_8bit_cte; if (pp->fmt == CMIT_FMT_USERFORMAT) { format_commit_message(commit, user_format, sb, pp); return; } encoding = get_log_output_encoding(); msg = reencoded = logmsg_reencode(commit, NULL, encoding); if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL) indent = 0; /* * We need to check and emit Content-type: to mark it * as 8-bit if we haven't done so. */ if (pp->fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) { int i, ch, in_body; for (in_body = i = 0; (ch = msg[i]); i++) { if (!in_body) { /* author could be non 7-bit ASCII but * the log may be so; skip over the * header part first. */ if (ch == '\n' && msg[i+1] == '\n') in_body = 1; } else if (non_ascii(ch)) { need_8bit_cte = 1; break; } } } pp_header(pp, encoding, commit, &msg, sb); if (pp->fmt != CMIT_FMT_ONELINE && !pp->subject) { strbuf_addch(sb, '\n'); } /* Skip excess blank lines at the beginning of body, if any... */ msg = skip_empty_lines(msg); /* These formats treat the title line specially. */ if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL) pp_title_line(pp, &msg, sb, encoding, need_8bit_cte); beginning_of_body = sb->len; if (pp->fmt != CMIT_FMT_ONELINE) pp_remainder(pp, &msg, sb, indent); strbuf_rtrim(sb); /* Make sure there is an EOLN for the non-oneline case */ if (pp->fmt != CMIT_FMT_ONELINE) strbuf_addch(sb, '\n'); /* * The caller may append additional body text in e-mail * format. Make sure we did not strip the blank line * between the header and the body. */ if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); unuse_commit_buffer(commit, reencoded); }
static int parse_commit(struct strbuf* input, struct string_list* files, struct strbuf* message) { int err; int pos; struct strbuf line; int lineno = 0; enum { BEGIN, FILES, MESSAGE } state = BEGIN; enum { OK, FAILED } result = OK; // if there is no data, just return if (input->len == 0) { return 0; } strbuf_init(&line, 0); pos = 0; while (result == OK) { err = get_strbuf_line(input, &pos, &line); lineno++; if (err != 0) { break; } if (is_comment(&line)) { continue; } switch (state) { case BEGIN: strbuf_trim(&line); if (line.len != 0) { if (0 == strcmp(line.buf, "Files:")) { state = FILES; } else { result = FAILED; } } break; case FILES: strbuf_trim(&line); if (line.len != 0) { if (0 == strcmp(line.buf, "Commit Message:")) { state = MESSAGE; } else if (0 == strip_file_info(&line)) { string_list_insert(line.buf, files); } else { result = FAILED; } } break; case MESSAGE: strbuf_rtrim(&line); strbuf_addbuf(message, &line); strbuf_addch(message, '\n'); break; } } strbuf_trim(message); return result == OK ? 0 : 1; }
// Convert a node_block list to HTML. Returns 0 on success, and sets result. static void blocks_to_html(strbuf *html, node_block *b) { struct ListData *data; render_stack* rstack = NULL; bool visit_children = false; bool tight = false; while(b != NULL) { visit_children = false; switch(b->tag) { case BLOCK_DOCUMENT: rstack = push_block(rstack, b->next, "", false, false); visit_children = true; break; case BLOCK_PARAGRAPH: if (tight) { inlines_to_html(html, b->inline_content); } else { cr(html); strbuf_puts(html, "<p>"); inlines_to_html(html, b->inline_content); strbuf_puts(html, "</p>\n"); } break; case BLOCK_BQUOTE: cr(html); strbuf_puts(html, "<blockquote>\n"); rstack = push_block(rstack, b->next, "</blockquote>\n", tight, false); tight = false; visit_children = true; break; case BLOCK_LIST_ITEM: cr(html); strbuf_puts(html, "<li>"); rstack = push_block(rstack, b->next, "</li>\n", tight, true); visit_children = true; break; case BLOCK_LIST: // make sure a list starts at the beginning of the line: cr(html); data = &(b->as.list); if (data->start > 1) { strbuf_printf(html, "<%s start=\"%d\">\n", data->list_type == bullet ? "ul" : "ol", data->start); } else { strbuf_puts(html, data->list_type == bullet ? "<ul>\n" : "<ol>\n"); } rstack = push_block(rstack, b->next, data->list_type == bullet ? "\n</ul>\n" : "\n</ol>\n", tight, false); tight = data->tight; visit_children = true; break; case BLOCK_ATX_HEADER: case BLOCK_SETEXT_HEADER: cr(html); strbuf_printf(html, "<h%d>", b->as.header.level); inlines_to_html(html, b->inline_content); strbuf_printf(html, "</h%d>\n", b->as.header.level); break; case BLOCK_INDENTED_CODE: case BLOCK_FENCED_CODE: cr(html); strbuf_puts(html, "<pre><code"); if (b->tag == BLOCK_FENCED_CODE) { strbuf *info = &b->as.code.info; if (strbuf_len(info) > 0) { int first_tag = strbuf_strchr(info, ' ', 0); if (first_tag < 0) first_tag = strbuf_len(info); strbuf_puts(html, " class=\"language-"); escape_html(html, info->ptr, first_tag); strbuf_putc(html, '"'); } } strbuf_putc(html, '>'); escape_html(html, b->string_content.ptr, b->string_content.size); strbuf_puts(html, "</code></pre>\n"); break; case BLOCK_HTML: strbuf_put(html, b->string_content.ptr, b->string_content.size); break; case BLOCK_HRULE: strbuf_puts(html, "<hr />\n"); break; case BLOCK_REFERENCE_DEF: break; default: assert(false); } if (visit_children) { b = b->children; } else { b = b->next; } while (b == NULL && rstack != NULL) { strbuf_puts(html, rstack->literal); if (rstack->trim) { strbuf_rtrim(html); } tight = rstack->tight; b = rstack->next_sibling.block; rstack = pop_render_stack(rstack); } } free_render_stack(rstack); }
/* * Reads the patches into a string list, with the `util` field being populated * as struct object_id (will need to be free()d). */ static int read_patches(const char *range, struct string_list *list) { struct child_process cp = CHILD_PROCESS_INIT; FILE *in; struct strbuf buf = STRBUF_INIT, line = STRBUF_INIT; struct patch_util *util = NULL; int in_header = 1; argv_array_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges", "--reverse", "--date-order", "--decorate=no", "--no-abbrev-commit", range, NULL); cp.out = -1; cp.no_stdin = 1; cp.git_cmd = 1; if (start_command(&cp)) return error_errno(_("could not start `log`")); in = fdopen(cp.out, "r"); if (!in) { error_errno(_("could not read `log` output")); finish_command(&cp); return -1; } while (strbuf_getline(&line, in) != EOF) { const char *p; if (skip_prefix(line.buf, "commit ", &p)) { if (util) { string_list_append(list, buf.buf)->util = util; strbuf_reset(&buf); } util = xcalloc(sizeof(*util), 1); if (get_oid(p, &util->oid)) { error(_("could not parse commit '%s'"), p); free(util); string_list_clear(list, 1); strbuf_release(&buf); strbuf_release(&line); fclose(in); finish_command(&cp); return -1; } util->matching = -1; in_header = 1; continue; } if (starts_with(line.buf, "diff --git")) { in_header = 0; strbuf_addch(&buf, '\n'); if (!util->diff_offset) util->diff_offset = buf.len; strbuf_addbuf(&buf, &line); } else if (in_header) { if (starts_with(line.buf, "Author: ")) { strbuf_addbuf(&buf, &line); strbuf_addstr(&buf, "\n\n"); } else if (starts_with(line.buf, " ")) { strbuf_rtrim(&line); strbuf_addbuf(&buf, &line); strbuf_addch(&buf, '\n'); } continue; } else if (starts_with(line.buf, "@@ ")) strbuf_addstr(&buf, "@@"); else if (!line.buf[0] || starts_with(line.buf, "index ")) /* * A completely blank (not ' \n', which is context) * line is not valid in a diff. We skip it * silently, because this neatly handles the blank * separator line between commits in git-log * output. * * We also want to ignore the diff's `index` lines * because they contain exact blob hashes in which * we are not interested. */ continue; else strbuf_addbuf(&buf, &line); strbuf_addch(&buf, '\n'); util->diffsize++; } fclose(in); strbuf_release(&line); if (util) string_list_append(list, buf.buf)->util = util; strbuf_release(&buf); if (finish_command(&cp)) return -1; return 0; }
void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, struct strbuf *sb, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode, int need_8bit_cte) { unsigned long beginning_of_body; int indent = 4; const char *msg = commit->buffer; char *reencoded; const char *encoding; if (fmt == CMIT_FMT_USERFORMAT) { format_commit_message(commit, user_format, sb); return; } encoding = (git_log_output_encoding ? git_log_output_encoding : git_commit_encoding); if (!encoding) encoding = "utf-8"; reencoded = logmsg_reencode(commit, encoding); if (reencoded) { msg = reencoded; } if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) indent = 0; /* * We need to check and emit Content-type: to mark it * as 8-bit if we haven't done so. */ if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) { int i, ch, in_body; for (in_body = i = 0; (ch = msg[i]); i++) { if (!in_body) { /* author could be non 7-bit ASCII but * the log may be so; skip over the * header part first. */ if (ch == '\n' && msg[i+1] == '\n') in_body = 1; } else if (non_ascii(ch)) { need_8bit_cte = 1; break; } } } pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb); if (fmt != CMIT_FMT_ONELINE && !subject) { strbuf_addch(sb, '\n'); } /* Skip excess blank lines at the beginning of body, if any... */ for (;;) { int linelen = get_one_line(msg); int ll = linelen; if (!linelen) break; if (!is_empty_line(msg, &ll)) break; msg += linelen; } /* These formats treat the title line specially. */ if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) pp_title_line(fmt, &msg, sb, subject, after_subject, encoding, need_8bit_cte); beginning_of_body = sb->len; if (fmt != CMIT_FMT_ONELINE) pp_remainder(fmt, &msg, sb, indent); strbuf_rtrim(sb); /* Make sure there is an EOLN for the non-oneline case */ if (fmt != CMIT_FMT_ONELINE) strbuf_addch(sb, '\n'); /* * The caller may append additional body text in e-mail * format. Make sure we did not strip the blank line * between the header and the body. */ if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); free(reencoded); }