From: Junio C Hamano Date: Wed, 9 Jul 2014 18:33:27 +0000 (-0700) Subject: Merge branch 'jk/skip-prefix' X-Git-Tag: v2.1.0-rc0~64 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/e91ae32a01ffe294b8510c1d8cd7138493a0712f?ds=inline;hp=-c Merge branch 'jk/skip-prefix' * jk/skip-prefix: http-push: refactor parsing of remote object names imap-send: use skip_prefix instead of using magic numbers use skip_prefix to avoid repeated calculations git: avoid magic number with skip_prefix fetch-pack: refactor parsing in get_ack fast-import: refactor parsing of spaces stat_opt: check extra strlen call daemon: use skip_prefix to avoid magic numbers fast-import: use skip_prefix for parsing input use skip_prefix to avoid repeating strings use skip_prefix to avoid magic numbers transport-helper: avoid reading past end-of-string fast-import: fix read of uninitialized argv memory apply: use skip_prefix instead of raw addition refactor skip_prefix to return a boolean avoid using skip_prefix as a boolean daemon: mark some strings as const parse_diff_color_slot: drop ofs parameter --- e91ae32a01ffe294b8510c1d8cd7138493a0712f diff --combined builtin/commit.c index 84cec9a715,ec75341238..461c3b1cad --- a/builtin/commit.c +++ b/builtin/commit.c @@@ -1020,7 -1020,7 +1020,7 @@@ static int message_is_empty(struct strb static int template_untouched(struct strbuf *sb) { struct strbuf tmpl = STRBUF_INIT; - char *start; + const char *start; if (cleanup_mode == CLEANUP_NONE && sb->len) return 0; @@@ -1029,8 -1029,7 +1029,7 @@@ return 0; stripspace(&tmpl, cleanup_mode == CLEANUP_ALL); - start = (char *)skip_prefix(sb->buf, tmpl.buf); - if (!start) + if (!skip_prefix(sb->buf, tmpl.buf, &start)) start = sb->buf; strbuf_release(&tmpl); return rest_is_empty(sb, start - sb->buf); @@@ -1745,8 -1744,8 +1744,8 @@@ int cmd_commit(int argc, const char **a append_merge_tag_headers(parents, &tail); } - if (commit_tree_extended(&sb, active_cache_tree->sha1, parents, sha1, - author_ident.buf, sign_commit, extra)) { + if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->sha1, + parents, sha1, author_ident.buf, sign_commit, extra)) { rollback_index_files(); die(_("failed to write commit object")); } diff --combined builtin/fmt-merge-msg.c index ef8b254ef2,ad3bc58c74..971e802c6f --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@@ -100,7 -100,8 +100,8 @@@ static int handle_line(char *line, stru { int i, len = strlen(line); struct origin_data *origin_data; - char *src, *origin; + char *src; + const char *origin; struct src_data *src_data; struct string_list_item *item; int pulling_head = 0; @@@ -164,8 -165,7 +165,7 @@@ origin = line; string_list_append(&src_data->tag, origin + 4); src_data->head_status |= 2; - } else if (starts_with(line, "remote-tracking branch ")) { - origin = line + strlen("remote-tracking branch "); + } else if (skip_prefix(line, "remote-tracking branch ", &origin)) { string_list_append(&src_data->r_branch, origin); src_data->head_status |= 2; } else { @@@ -230,14 -230,12 +230,14 @@@ static void add_branch_desc(struct strb static void record_person(int which, struct string_list *people, struct commit *commit) { + const char *buffer; char *name_buf, *name, *name_end; struct string_list_item *elem; const char *field; field = (which == 'a') ? "\nauthor " : "\ncommitter "; - name = strstr(commit->buffer, field); + buffer = get_commit_buffer(commit, NULL); + name = strstr(buffer, field); if (!name) return; name += strlen(field); @@@ -249,7 -247,6 +249,7 @@@ if (name_end < name) return; name_buf = xmemdupz(name, name_end - name + 1); + unuse_commit_buffer(commit, buffer); elem = string_list_lookup(people, name_buf); if (!elem) { @@@ -300,8 -297,8 +300,8 @@@ static void credit_people(struct strbu if (!them->nr || (them->nr == 1 && me && - (me = skip_prefix(me, them->items->string)) != NULL && - skip_prefix(me, " <"))) + skip_prefix(me, them->items->string, &me) && + starts_with(me, " <"))) return; strbuf_addf(out, "\n%c %s ", comment_line_char, label); add_people_count(out, them); diff --combined builtin/log.c index 92063dfc48,0f59c25d36..27c1b65db4 --- a/builtin/log.c +++ b/builtin/log.c @@@ -347,7 -347,8 +347,7 @@@ static int cmd_log_walk(struct rev_inf rev->max_count++; if (!rev->reflog_info) { /* we allow cycles in reflog ancestry */ - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); } free_commit_list(commit->parents); commit->parents = NULL; @@@ -871,7 -872,7 +871,7 @@@ static char *find_branch_name(struct re int i, positive = -1; unsigned char branch_sha1[20]; const unsigned char *tip_sha1; - const char *ref; + const char *ref, *v; char *full_ref, *branch = NULL; for (i = 0; i < rev->cmdline.nr; i++) { @@@ -887,9 -888,9 +887,9 @@@ ref = rev->cmdline.rev[positive].name; tip_sha1 = rev->cmdline.rev[positive].item->sha1; if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) && - starts_with(full_ref, "refs/heads/") && + skip_prefix(full_ref, "refs/heads/", &v) && !hashcmp(tip_sha1, branch_sha1)) - branch = xstrdup(full_ref + strlen("refs/heads/")); + branch = xstrdup(v); free(full_ref); return branch; } @@@ -924,12 -925,9 +924,12 @@@ static void make_cover_letter(struct re log_write_email_headers(rev, head, &pp.subject, &pp.after_subject, &need_8bit_cte); - for (i = 0; !need_8bit_cte && i < nr; i++) - if (has_non_ascii(list[i]->buffer)) + for (i = 0; !need_8bit_cte && i < nr; i++) { + const char *buf = get_commit_buffer(list[i], NULL); + if (has_non_ascii(buf)) need_8bit_cte = 1; + unuse_commit_buffer(list[i], buf); + } if (!branch_name) branch_name = find_branch_name(rev); @@@ -1396,10 -1394,10 +1396,10 @@@ int cmd_format_patch(int argc, const ch if (check_head) { unsigned char sha1[20]; - const char *ref; + const char *ref, *v; ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL); - if (ref && starts_with(ref, "refs/heads/")) - branch_name = xstrdup(ref + strlen("refs/heads/")); + if (ref && skip_prefix(ref, "refs/heads/", &v)) + branch_name = xstrdup(v); else branch_name = xstrdup(""); /* no branch */ } @@@ -1530,7 -1528,8 +1530,7 @@@ reopen_stdout(rev.numbered_files ? NULL : commit, NULL, &rev, quiet)) die(_("Failed to create output files")); shown = log_tree_commit(&rev, commit); - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); /* We put one extra blank line between formatted * patches and this flag is used by log-tree code diff --combined commit.c index 4ff8077dbf,dfc0eb0241..fb7897c2a4 --- a/commit.c +++ b/commit.c @@@ -17,6 -17,7 +17,6 @@@ static struct commit_extra_header *read int save_commit_buffer = 1; const char *commit_type = "commit"; -static int commit_count; static struct commit *check_commit(struct object *obj, const unsigned char *sha1, @@@ -63,6 -64,7 +63,6 @@@ struct commit *lookup_commit(const unsi struct object *obj = lookup_object(sha1); if (!obj) { struct commit *c = alloc_commit_node(); - c->index = commit_count++; return create_object(sha1, OBJ_COMMIT, c); } if (!obj->type) @@@ -245,76 -247,6 +245,76 @@@ int unregister_shallow(const unsigned c return 0; } +struct commit_buffer { + void *buffer; + unsigned long size; +}; +define_commit_slab(buffer_slab, struct commit_buffer); +static struct buffer_slab buffer_slab = COMMIT_SLAB_INIT(1, buffer_slab); + +void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + v->buffer = buffer; + v->size = size; +} + +const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + if (sizep) + *sizep = v->size; + return v->buffer; +} + +const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep) +{ + const void *ret = get_cached_commit_buffer(commit, sizep); + if (!ret) { + enum object_type type; + unsigned long size; + ret = read_sha1_file(commit->object.sha1, &type, &size); + if (!ret) + die("cannot read commit object %s", + sha1_to_hex(commit->object.sha1)); + if (type != OBJ_COMMIT) + die("expected commit for %s, got %s", + sha1_to_hex(commit->object.sha1), typename(type)); + if (sizep) + *sizep = size; + } + return ret; +} + +void unuse_commit_buffer(const struct commit *commit, const void *buffer) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + if (v->buffer != buffer) + free((void *)buffer); +} + +void free_commit_buffer(struct commit *commit) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + free(v->buffer); + v->buffer = NULL; + v->size = 0; +} + +const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + void *ret; + + ret = v->buffer; + if (sizep) + *sizep = v->size; + + v->buffer = NULL; + v->size = 0; + return ret; +} + int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size) { const char *tail = buffer; @@@ -392,7 -324,7 +392,7 @@@ int parse_commit(struct commit *item } ret = parse_commit_buffer(item, buffer, size); if (save_commit_buffer && !ret) { - item->buffer = buffer; + set_commit_buffer(item, buffer, size); return 0; } free(buffer); @@@ -607,15 -539,24 +607,14 @@@ static void record_author_date(struct a struct commit *commit) { const char *buf, *line_end, *ident_line; - char *buffer = NULL; + const char *buffer = get_commit_buffer(commit, NULL); struct ident_split ident; char *date_end; unsigned long date; - if (!commit->buffer) { - unsigned long size; - enum object_type type; - buffer = read_sha1_file(commit->object.sha1, &type, &size); - if (!buffer) - return; - } - - for (buf = commit->buffer ? commit->buffer : buffer; - buf; - buf = line_end + 1) { + for (buf = buffer; buf; buf = line_end + 1) { line_end = strchrnul(buf, '\n'); - ident_line = skip_prefix(buf, "author "); - if (!ident_line) { + if (!skip_prefix(buf, "author ", &ident_line)) { if (!line_end[0] || line_end[1] == '\n') return; /* end of header */ continue; @@@ -633,7 -574,7 +632,7 @@@ *(author_date_slab_at(author_date, commit)) = date; fail_exit: - free(buffer); + unuse_commit_buffer(commit, buffer); } static int compare_commits_by_author_date(const void *a_, const void *b_, @@@ -1138,14 -1079,17 +1137,14 @@@ static int do_sign_commit(struct strbu return 0; } -int parse_signed_commit(const unsigned char *sha1, +int parse_signed_commit(const struct commit *commit, struct strbuf *payload, struct strbuf *signature) { + unsigned long size; - enum object_type type; - char *buffer = read_sha1_file(sha1, &type, &size); + const char *buffer = get_commit_buffer(commit, &size); int in_signature, saw_signature = -1; - char *line, *tail; - - if (!buffer || type != OBJ_COMMIT) - goto cleanup; + const char *line, *tail; line = buffer; tail = buffer + size; @@@ -1153,7 -1097,7 +1152,7 @@@ saw_signature = 0; while (line < tail) { const char *sig = NULL; - char *next = memchr(line, '\n', tail - line); + const char *next = memchr(line, '\n', tail - line); next = next ? next + 1 : tail; if (in_signature && line[0] == ' ') @@@ -1174,7 -1118,8 +1173,7 @@@ } line = next; } - cleanup: - free(buffer); + unuse_commit_buffer(commit, buffer); return saw_signature; } @@@ -1237,8 -1182,7 +1236,7 @@@ static void parse_gpg_output(struct sig for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { const char *found, *next; - found = skip_prefix(buf, sigcheck_gpg_status[i].check + 1); - if (!found) { + if (!skip_prefix(buf, sigcheck_gpg_status[i].check + 1, &found)) { found = strstr(buf, sigcheck_gpg_status[i].check); if (!found) continue; @@@ -1265,7 -1209,8 +1263,7 @@@ void check_commit_signature(const struc sigc->result = 'N'; - if (parse_signed_commit(commit->object.sha1, - &payload, &signature) <= 0) + if (parse_signed_commit(commit, &payload, &signature) <= 0) goto out; status = verify_signed_buffer(payload.buf, payload.len, signature.buf, signature.len, @@@ -1310,9 -1255,11 +1308,9 @@@ struct commit_extra_header *read_commit { struct commit_extra_header *extra = NULL; unsigned long size; - enum object_type type; - char *buffer = read_sha1_file(commit->object.sha1, &type, &size); - if (buffer && type == OBJ_COMMIT) - extra = read_commit_extra_header_lines(buffer, size, exclude); - free(buffer); + const char *buffer = get_commit_buffer(commit, &size); + extra = read_commit_extra_header_lines(buffer, size, exclude); + unuse_commit_buffer(commit, buffer); return extra; } @@@ -1395,8 -1342,7 +1393,8 @@@ void free_commit_extra_headers(struct c } } -int commit_tree(const struct strbuf *msg, const unsigned char *tree, +int commit_tree(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit) { @@@ -1404,7 -1350,7 +1402,7 @@@ int result; append_merge_tag_headers(parents, &tail); - result = commit_tree_extended(msg, tree, parents, ret, + result = commit_tree_extended(msg, msg_len, tree, parents, ret, author, sign_commit, extra); free_commit_extra_headers(extra); return result; @@@ -1525,8 -1471,7 +1523,8 @@@ static const char commit_utf8_warn[] "You may want to amend it after fixing the message, or set the config\n" "variable i18n.commitencoding to the encoding your project uses.\n"; -int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree, +int commit_tree_extended(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit, struct commit_extra_header *extra) @@@ -1537,7 -1482,7 +1535,7 @@@ assert_sha1_type(tree, OBJ_TREE); - if (memchr(msg->buf, '\0', msg->len)) + if (memchr(msg, '\0', msg_len)) return error("a NUL byte in commit log message not allowed."); /* Not having i18n.commitencoding is the same as having utf-8 */ @@@ -1576,7 -1521,7 +1574,7 @@@ strbuf_addch(&buffer, '\n'); /* And add the comment */ - strbuf_addbuf(&buffer, msg); + strbuf_add(&buffer, msg, msg_len); /* And check the encoding */ if (encoding_is_utf8 && !verify_utf8(&buffer)) diff --combined fetch-pack.c index b12bd4c59a,72ec520fda..b8a58fa7a5 --- a/fetch-pack.c +++ b/fetch-pack.c @@@ -189,20 -189,23 +189,23 @@@ static enum ack_type get_ack(int fd, un { int len; char *line = packet_read_line(fd, &len); + const char *arg; if (!len) die("git fetch-pack: expected ACK/NAK, got EOF"); if (!strcmp(line, "NAK")) return NAK; - if (starts_with(line, "ACK ")) { - if (!get_sha1_hex(line+4, result_sha1)) { - if (len < 45) + if (skip_prefix(line, "ACK ", &arg)) { + if (!get_sha1_hex(arg, result_sha1)) { + arg += 40; + len -= arg - line; + if (len < 1) return ACK; - if (strstr(line+45, "continue")) + if (strstr(arg, "continue")) return ACK_continue; - if (strstr(line+45, "common")) + if (strstr(arg, "common")) return ACK_common; - if (strstr(line+45, "ready")) + if (strstr(arg, "ready")) return ACK_ready; return ACK; } @@@ -319,18 -322,19 +322,19 @@@ static int find_common(struct fetch_pac if (args->depth > 0) { char *line; + const char *arg; unsigned char sha1[20]; send_request(args, fd[1], &req_buf); while ((line = packet_read_line(fd[0], NULL))) { - if (starts_with(line, "shallow ")) { - if (get_sha1_hex(line + 8, sha1)) + if (skip_prefix(line, "shallow ", &arg)) { + if (get_sha1_hex(arg, sha1)) die("invalid shallow line: %s", line); register_shallow(sha1); continue; } - if (starts_with(line, "unshallow ")) { - if (get_sha1_hex(line + 10, sha1)) + if (skip_prefix(line, "unshallow ", &arg)) { + if (get_sha1_hex(arg, sha1)) die("invalid unshallow line: %s", line); if (!lookup_object(sha1)) die("object not found: %s", line); @@@ -507,7 -511,7 +511,7 @@@ static void filter_refs(struct fetch_pa int keep = 0; next = ref->next; - if (!memcmp(ref->name, "refs/", 5) && + if (starts_with(ref->name, "refs/") && check_refname_format(ref->name, 0)) ; /* trash */ else { diff --combined fsck.c index a7233c8d0b,bdbea2b995..a4e8593e78 --- a/fsck.c +++ b/fsck.c @@@ -276,23 -276,20 +276,20 @@@ static int fsck_ident(const char **iden return 0; } -static int fsck_commit(struct commit *commit, fsck_error error_func) +static int fsck_commit_buffer(struct commit *commit, const char *buffer, + fsck_error error_func) { - const char *tmp; - const char *buffer = commit->buffer; unsigned char tree_sha1[20], sha1[20]; struct commit_graft *graft; int parents = 0; int err; - buffer = skip_prefix(buffer, "tree "); - if (!buffer) + if (!skip_prefix(buffer, "tree ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line"); if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n') return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1"); buffer += 41; - while ((tmp = skip_prefix(buffer, "parent "))) { - buffer = tmp; + while (skip_prefix(buffer, "parent ", &buffer)) { if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1"); buffer += 41; @@@ -319,14 -316,12 +316,12 @@@ if (p || parents) return error_func(&commit->object, FSCK_ERROR, "parent objects missing"); } - buffer = skip_prefix(buffer, "author "); - if (!buffer) + if (!skip_prefix(buffer, "author ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line"); err = fsck_ident(&buffer, &commit->object, error_func); if (err) return err; - buffer = skip_prefix(buffer, "committer "); - if (!buffer) + if (!skip_prefix(buffer, "committer ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'committer' line"); err = fsck_ident(&buffer, &commit->object, error_func); if (err) @@@ -337,14 -332,6 +332,14 @@@ return 0; } +static int fsck_commit(struct commit *commit, fsck_error error_func) +{ + const char *buffer = get_commit_buffer(commit, NULL); + int ret = fsck_commit_buffer(commit, buffer, error_func); + unuse_commit_buffer(commit, buffer); + return ret; +} + static int fsck_tag(struct tag *tag, fsck_error error_func) { struct object *tagged = tag->tagged; diff --combined git-compat-util.h index 96f55547a3,d29e1dff08..9de3180710 --- a/git-compat-util.h +++ b/git-compat-util.h @@@ -349,13 -349,32 +349,32 @@@ extern void set_die_is_recursing_routin extern int starts_with(const char *str, const char *prefix); extern int ends_with(const char *str, const char *suffix); - static inline const char *skip_prefix(const char *str, const char *prefix) + /* + * If the string "str" begins with the string found in "prefix", return 1. + * The "out" parameter is set to "str + strlen(prefix)" (i.e., to the point in + * the string right after the prefix). + * + * Otherwise, return 0 and leave "out" untouched. + * + * Examples: + * + * [extract branch name, fail if not a branch] + * if (!skip_prefix(ref, "refs/heads/", &branch) + * return -1; + * + * [skip prefix if present, otherwise use whole string] + * skip_prefix(name, "refs/heads/", &name); + */ + static inline int skip_prefix(const char *str, const char *prefix, + const char **out) { do { - if (!*prefix) - return str; + if (!*prefix) { + *out = str; + return 1; + } } while (*str++ == *prefix++); - return NULL; + return 0; } #if defined(NO_MMAP) || defined(USE_WIN32_MMAP) @@@ -685,17 -704,6 +704,17 @@@ void git_qsort(void *base, size_t nmemb #endif #endif +#if defined(__GNUC__) && defined(__x86_64__) +#include +/* + * This is the system memory page size; it's used so that we can read + * outside the bounds of an allocation without segfaulting. + */ +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif +#endif + #ifdef UNRELIABLE_FSTAT #define fstat_is_reliable() 0 #else diff --combined git.c index d6b4a5543f,1537f00bc7..dd54f5734a --- a/git.c +++ b/git.c @@@ -20,43 -20,6 +20,43 @@@ const char git_more_info_string[] static struct startup_info git_startup_info; static int use_pager = -1; +static char orig_cwd[PATH_MAX]; +static const char *env_names[] = { + GIT_DIR_ENVIRONMENT, + GIT_WORK_TREE_ENVIRONMENT, + GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, + GIT_PREFIX_ENVIRONMENT +}; +static char *orig_env[4]; +static int saved_environment; + +static void save_env(void) +{ + int i; + if (saved_environment) + return; + saved_environment = 1; + if (!getcwd(orig_cwd, sizeof(orig_cwd))) + die_errno("cannot getcwd"); + for (i = 0; i < ARRAY_SIZE(env_names); i++) { + orig_env[i] = getenv(env_names[i]); + if (orig_env[i]) + orig_env[i] = xstrdup(orig_env[i]); + } +} + +static void restore_env(void) +{ + int i; + if (*orig_cwd && chdir(orig_cwd)) + die_errno("could not move to %s", orig_cwd); + for (i = 0; i < ARRAY_SIZE(env_names); i++) { + if (orig_env[i]) + setenv(env_names[i], orig_env[i], 1); + else + unsetenv(env_names[i]); + } +} static void commit_pager_choice(void) { switch (use_pager) { @@@ -91,8 -54,7 +91,7 @@@ static int handle_options(const char ** /* * Check remaining flags. */ - if (starts_with(cmd, "--exec-path")) { - cmd += 11; + if (skip_prefix(cmd, "--exec-path", &cmd)) { if (*cmd == '=') git_set_argv_exec_path(cmd + 1); else { @@@ -129,8 -91,8 +128,8 @@@ *envchanged = 1; (*argv)++; (*argc)--; - } else if (starts_with(cmd, "--git-dir=")) { - setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); + } else if (skip_prefix(cmd, "--git-dir=", &cmd)) { + setenv(GIT_DIR_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--namespace")) { @@@ -143,8 -105,8 +142,8 @@@ *envchanged = 1; (*argv)++; (*argc)--; - } else if (starts_with(cmd, "--namespace=")) { - setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1); + } else if (skip_prefix(cmd, "--namespace=", &cmd)) { + setenv(GIT_NAMESPACE_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { @@@ -157,8 -119,8 +156,8 @@@ *envchanged = 1; (*argv)++; (*argc)--; - } else if (starts_with(cmd, "--work-tree=")) { - setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1); + } else if (skip_prefix(cmd, "--work-tree=", &cmd)) { + setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--bare")) { @@@ -309,7 -271,6 +308,7 @@@ static int handle_alias(int *argcp, con * RUN_SETUP for reading from the configuration file. */ #define NEED_WORK_TREE (1<<3) +#define NO_SETUP (1<<4) struct cmd_struct { const char *cmd; @@@ -390,7 -351,7 +389,7 @@@ static struct cmd_struct commands[] = { "cherry", cmd_cherry, RUN_SETUP }, { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE }, { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE }, - { "clone", cmd_clone }, + { "clone", cmd_clone, NO_SETUP }, { "column", cmd_column, RUN_SETUP_GENTLY }, { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE }, { "commit-tree", cmd_commit_tree, RUN_SETUP }, @@@ -416,8 -377,8 +415,8 @@@ { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY }, - { "init", cmd_init_db }, - { "init-db", cmd_init_db }, + { "init", cmd_init_db, NO_SETUP }, + { "init-db", cmd_init_db, NO_SETUP }, { "log", cmd_log, RUN_SETUP }, { "ls-files", cmd_ls_files, RUN_SETUP }, { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, @@@ -522,10 -483,6 +521,10 @@@ static void handle_builtin(int argc, co struct cmd_struct *p = commands+i; if (strcmp(p->cmd, cmd)) continue; + if (saved_environment && (p->option & NO_SETUP)) { + restore_env(); + break; + } exit(run_builtin(p, argc, argv)); } } @@@ -581,10 -538,7 +580,10 @@@ static int run_argv(int *argcp, const c * of overriding "git log" with "git show" by having * alias.log = show */ - if (done_alias || !handle_alias(argcp, argv)) + if (done_alias) + break; + save_env(); + if (!handle_alias(argcp, argv)) break; done_alias = 1; } @@@ -623,8 -577,7 +622,7 @@@ int main(int argc, char **av * So we just directly call the builtin handler, and die if * that one cannot handle it. */ - if (starts_with(cmd, "git-")) { - cmd += 4; + if (skip_prefix(cmd, "git-", &cmd)) { argv[0] = cmd; handle_builtin(argc, argv); die("cannot handle %s as a builtin", cmd); @@@ -635,8 -588,8 +633,8 @@@ argc--; handle_options(&argv, &argc, NULL); if (argc > 0) { - if (starts_with(argv[0], "--")) - argv[0] += 2; + /* translate --help and --version into commands */ + skip_prefix(argv[0], "--", &argv[0]); } else { /* The user didn't specify a command; give them help */ commit_pager_choice(); diff --combined http.c index 3a28b219be,f04621e61d..c8cd50dd0c --- a/http.c +++ b/http.c @@@ -927,7 -927,7 +927,7 @@@ static int extract_param(const char *ra return -1; raw++; - while (*raw && !isspace(*raw)) + while (*raw && !isspace(*raw) && *raw != ';') strbuf_addch(out, *raw++); return 0; } @@@ -971,7 -971,7 +971,7 @@@ static void extract_content_type(struc strbuf_reset(charset); while (*p) { - while (isspace(*p)) + while (isspace(*p) || *p == ';') p++; if (!extract_param(p, "charset", charset)) return; @@@ -1087,11 -1087,10 +1087,10 @@@ static int update_url_from_redirect(str if (!strcmp(asked, got->buf)) return 0; - if (!starts_with(asked, base->buf)) + if (!skip_prefix(asked, base->buf, &tail)) die("BUG: update_url_from_redirect: %s is not a superset of %s", asked, base->buf); - tail = asked + base->len; tail_len = strlen(tail); if (got->len < tail_len || diff --combined merge-recursive.c index d38a3b2eb5,f848001817..e6e1fa33fd --- a/merge-recursive.c +++ b/merge-recursive.c @@@ -40,7 -40,7 +40,7 @@@ static struct tree *shift_tree_object(s static struct commit *make_virtual_commit(struct tree *tree, const char *comment) { - struct commit *commit = xcalloc(1, sizeof(struct commit)); + struct commit *commit = alloc_commit_node(); struct merge_remote_desc *desc = xmalloc(sizeof(*desc)); desc->name = comment; @@@ -190,11 -190,9 +190,11 @@@ static void output_commit_title(struct printf(_("(bad commit)\n")); else { const char *title; - int len = find_commit_subject(commit->buffer, &title); + const char *msg = get_commit_buffer(commit, NULL); + int len = find_commit_subject(msg, &title); if (len) printf("%.*s\n", len, title); + unuse_commit_buffer(commit, msg); } } } @@@ -2065,6 -2063,8 +2065,8 @@@ void init_merge_options(struct merge_op int parse_merge_opt(struct merge_options *o, const char *s) { + const char *arg; + if (!s || !*s) return -1; if (!strcmp(s, "ours")) @@@ -2073,14 -2073,14 +2075,14 @@@ o->recursive_variant = MERGE_RECURSIVE_THEIRS; else if (!strcmp(s, "subtree")) o->subtree_shift = ""; - else if (starts_with(s, "subtree=")) - o->subtree_shift = s + strlen("subtree="); + else if (skip_prefix(s, "subtree=", &arg)) + o->subtree_shift = arg; else if (!strcmp(s, "patience")) o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF); else if (!strcmp(s, "histogram")) o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF); - else if (starts_with(s, "diff-algorithm=")) { - long value = parse_algorithm_value(s + strlen("diff-algorithm=")); + else if (skip_prefix(s, "diff-algorithm=", &arg)) { + long value = parse_algorithm_value(arg); if (value < 0) return -1; /* clear out previous settings */ @@@ -2098,9 -2098,8 +2100,8 @@@ o->renormalize = 1; else if (!strcmp(s, "no-renormalize")) o->renormalize = 0; - else if (starts_with(s, "rename-threshold=")) { - const char *score = s + strlen("rename-threshold="); - if ((o->rename_score = parse_rename_score(&score)) == -1 || *score != 0) + else if (skip_prefix(s, "rename-threshold=", &arg)) { + if ((o->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0) return -1; } else diff --combined pretty.c index c93c14b080,f24752a85b..b5cf3d52c3 --- a/pretty.c +++ b/pretty.c @@@ -40,10 -40,9 +40,9 @@@ static int git_pretty_formats_config(co const char *fmt; int i; - if (!starts_with(var, "pretty.")) + if (!skip_prefix(var, "pretty.", &name)) return 0; - name = var + strlen("pretty."); for (i = 0; i < builtin_formats_len; i++) { if (!strcmp(commit_formats[i].name, name)) return 0; @@@ -274,7 -273,7 +273,7 @@@ static void add_rfc822_quoted(struct st enum rfc2047_type { RFC2047_SUBJECT, - RFC2047_ADDRESS, + RFC2047_ADDRESS }; static int is_rfc2047_special(char ch, enum rfc2047_type type) @@@ -606,16 -605,29 +605,16 @@@ static char *replace_encoding_header(ch return strbuf_detach(&tmp, NULL); } -char *logmsg_reencode(const struct commit *commit, - char **commit_encoding, - const char *output_encoding) +const char *logmsg_reencode(const struct commit *commit, + char **commit_encoding, + const char *output_encoding) { static const char *utf8 = "UTF-8"; const char *use_encoding; char *encoding; - char *msg = commit->buffer; + const char *msg = get_commit_buffer(commit, NULL); char *out; - if (!msg) { - enum object_type type; - unsigned long size; - - msg = read_sha1_file(commit->object.sha1, &type, &size); - if (!msg) - die("Cannot read commit object %s", - sha1_to_hex(commit->object.sha1)); - if (type != OBJ_COMMIT) - die("Expected commit for '%s', got %s", - sha1_to_hex(commit->object.sha1), typename(type)); - } - if (!output_encoding || !*output_encoding) { if (commit_encoding) *commit_encoding = @@@ -639,13 -651,12 +638,13 @@@ * Otherwise, we still want to munge the encoding header in the * result, which will be done by modifying the buffer. If we * are using a fresh copy, we can reuse it. But if we are using - * the cached copy from commit->buffer, we need to duplicate it - * to avoid munging commit->buffer. + * the cached copy from get_commit_buffer, we need to duplicate it + * to avoid munging the cached copy. */ - out = msg; - if (out == commit->buffer) - out = xstrdup(out); + if (msg == get_cached_commit_buffer(commit, NULL)) + out = xstrdup(msg); + else + out = (char *)msg; } else { /* @@@ -655,8 -666,8 +654,8 @@@ * copy, we can free it. */ out = reencode_string(msg, output_encoding, use_encoding); - if (out && msg != commit->buffer) - free(msg); + if (out) + unuse_commit_buffer(commit, msg); } /* @@@ -675,6 -686,12 +674,6 @@@ return out ? out : msg; } -void logmsg_free(char *msg, const struct commit *commit) -{ - if (msg != commit->buffer) - free(msg); -} - static int mailmap_name(const char **email, size_t *email_len, const char **name, size_t *name_len) { @@@ -778,7 -795,7 +777,7 @@@ struct format_commit_context struct signature_check signature_check; enum flush_type flush_type; enum trunc_type truncate; - char *message; + const char *message; char *commit_encoding; size_t width, indent1, indent2; int auto_color; @@@ -1518,7 -1535,7 +1517,7 @@@ void format_commit_message(const struc } free(context.commit_encoding); - logmsg_free(context.message, commit); + unuse_commit_buffer(commit, context.message); free(context.signature_check.gpg_output); free(context.signature_check.signer); } @@@ -1687,7 -1704,7 +1686,7 @@@ void pretty_print_commit(struct pretty_ unsigned long beginning_of_body; int indent = 4; const char *msg; - char *reencoded; + const char *reencoded; const char *encoding; int need_8bit_cte = pp->need_8bit_cte; @@@ -1754,7 -1771,7 +1753,7 @@@ if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); - logmsg_free(reencoded, commit); + unuse_commit_buffer(commit, reencoded); } void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit, diff --combined remote.c index ae04043203,30d2829c2b..a0c6ccf5b2 --- a/remote.c +++ b/remote.c @@@ -488,9 -488,8 +488,8 @@@ static void read_config(void current_branch = NULL; head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag); if (head_ref && (flag & REF_ISSYMREF) && - starts_with(head_ref, "refs/heads/")) { - current_branch = - make_branch(head_ref + strlen("refs/heads/"), 0); + skip_prefix(head_ref, "refs/heads/", &head_ref)) { + current_branch = make_branch(head_ref, 0); } git_config(handle_config, NULL); if (branch_pushremote_name) { @@@ -1194,7 -1193,7 +1193,7 @@@ static int match_explicit(struct ref *s case 1: break; case 0: - if (!memcmp(dst_value, "refs/", 5)) + if (starts_with(dst_value, "refs/")) matched_dst = make_linked_ref(dst_value, dst_tail); else if (is_null_sha1(matched_src->new_sha1)) error("unable to delete '%s': remote ref does not exist", diff --combined sha1_name.c index c2c938c4e1,72e6ac6a6e..a91e0c924b --- a/sha1_name.c +++ b/sha1_name.c @@@ -862,17 -862,27 +862,17 @@@ static int get_sha1_oneline(const char commit_list_insert(l->item, &backup); } while (list) { - char *p, *to_free = NULL; + const char *p, *buf; struct commit *commit; - enum object_type type; - unsigned long size; int matches; commit = pop_most_recent_commit(&list, ONELINE_SEEN); if (!parse_object(commit->object.sha1)) continue; - if (commit->buffer) - p = commit->buffer; - else { - p = read_sha1_file(commit->object.sha1, &type, &size); - if (!p) - continue; - to_free = p; - } - - p = strstr(p, "\n\n"); + buf = get_commit_buffer(commit, NULL); + p = strstr(buf, "\n\n"); matches = p && !regexec(®ex, p + 2, 0, NULL, 0); - free(to_free); + unuse_commit_buffer(commit, buf); if (matches) { hashcpy(sha1, commit->object.sha1); @@@ -901,10 -911,8 +901,8 @@@ static int grab_nth_branch_switch(unsig const char *match = NULL, *target = NULL; size_t len; - if (starts_with(message, "checkout: moving from ")) { - match = message + strlen("checkout: moving from "); + if (skip_prefix(message, "checkout: moving from ", &match)) target = strstr(match, " to "); - } if (!match || !target) return 0;