From: Junio C Hamano Date: Fri, 19 Sep 2014 18:38:39 +0000 (-0700) Subject: Merge branch 'rs/export-strbuf-addchars' X-Git-Tag: v2.2.0-rc0~103 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/56feed1c7641bbf7920efe6607c6a04309073baa?ds=inline;hp=-c Merge branch 'rs/export-strbuf-addchars' Code clean-up. * rs/export-strbuf-addchars: strbuf: use strbuf_addchars() for adding a char multiple times strbuf: export strbuf_addchars() --- 56feed1c7641bbf7920efe6607c6a04309073baa diff --combined Documentation/technical/api-strbuf.txt index 430302c2f4,1d83362116..cca6543234 --- a/Documentation/technical/api-strbuf.txt +++ b/Documentation/technical/api-strbuf.txt @@@ -7,10 -7,10 +7,10 @@@ use the mem* functions than a str* one Though, one has to be careful about the fact that str* functions often stop on NULs and that strbufs may have embedded NULs. -An strbuf is NUL terminated for convenience, but no function in the +A strbuf is NUL terminated for convenience, but no function in the strbuf API actually relies on the string being free of NULs. -strbufs has some invariants that are very important to keep in mind: +strbufs have some invariants that are very important to keep in mind: . The `buf` member is never NULL, so it can be used in any usual C string operations safely. strbuf's _have_ to be initialized either by @@@ -56,8 -56,8 +56,8 @@@ Data structure * `struct strbuf` This is the string buffer structure. The `len` member can be used to -determine the current length of the string, and `buf` member provides access to -the string itself. +determine the current length of the string, and `buf` member provides +access to the string itself. Functions --------- @@@ -121,28 -121,10 +121,28 @@@ * Related to the contents of the buffer +`strbuf_trim`:: + + Strip whitespace from the beginning and end of a string. + Equivalent to performing `strbuf_rtrim()` followed by `strbuf_ltrim()`. + `strbuf_rtrim`:: Strip whitespace from the end of a string. +`strbuf_ltrim`:: + + Strip whitespace from the beginning of a string. + +`strbuf_reencode`:: + + Replace the contents of the strbuf with a reencoded form. Returns -1 + on error, 0 on success. + +`strbuf_tolower`:: + + Lowercase each character in the buffer using `tolower`. + `strbuf_cmp`:: Compare two buffers. Returns an integer less than, equal to, or greater @@@ -160,6 -142,10 +160,10 @@@ then they will free() it Add a single character to the buffer. + `strbuf_addchars`:: + + Add a character the specified number of times to the buffer. + `strbuf_insert`:: Insert data to the given position of the buffer. The remaining contents @@@ -202,7 -188,7 +206,7 @@@ strbuf_addstr(sb, "immediate string") `strbuf_addbuf`:: - Copy the contents of an other buffer at the end of the current one. + Copy the contents of another buffer at the end of the current one. `strbuf_adddup`:: @@@ -307,16 -293,6 +311,16 @@@ same behaviour as well use it unless you need the correct position in the file descriptor. +`strbuf_getcwd`:: + + Set the buffer to the path of the current working directory. + +`strbuf_add_absolute_path` + + Add a path to a buffer, converting a relative path to an + absolute one in the process. Symbolic links are not + resolved. + `stripspace`:: Strip whitespace from a buffer. The second parameter controls if diff --combined merge-recursive.c index 8ab944c44c,ec0fef8d7d..22315c370a --- 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; @@@ -163,15 -163,13 +163,13 @@@ static void output(struct merge_option if (!show(o, v)) return; - strbuf_grow(&o->obuf, o->call_depth * 2 + 2); - memset(o->obuf.buf + o->obuf.len, ' ', o->call_depth * 2); - strbuf_setlen(&o->obuf, o->obuf.len + o->call_depth * 2); + strbuf_addchars(&o->obuf, ' ', o->call_depth * 2); va_start(ap, fmt); strbuf_vaddf(&o->obuf, fmt, ap); va_end(ap); - strbuf_add(&o->obuf, "\n", 1); + strbuf_addch(&o->obuf, '\n'); if (!o->buffer_output) flush_output(o); } @@@ -190,11 -188,9 +188,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); } } } @@@ -203,9 -199,7 +201,9 @@@ static int add_cacheinfo(unsigned int m const char *path, int stage, int refresh, int options) { struct cache_entry *ce; - ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh); + ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, + (refresh ? (CE_MATCH_REFRESH | + CE_MATCH_IGNORE_MISSING) : 0 )); if (!ce) return error(_("addinfo_cache failed for path '%s'"), path); return add_cache_entry(ce, options); @@@ -267,7 -261,9 +265,7 @@@ struct tree *write_tree_from_memory(str active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && - cache_tree_update(active_cache_tree, - (const struct cache_entry * const *)active_cache, - active_nr, 0) < 0) + cache_tree_update(&the_index, 0) < 0) die(_("error building trees")); result = lookup_tree(active_cache_tree->sha1); @@@ -589,48 -585,31 +587,48 @@@ static int remove_file(struct merge_opt return -1; } if (update_working_directory) { + if (ignore_case) { + struct cache_entry *ce; + ce = cache_file_exists(path, strlen(path), ignore_case); + if (ce && ce_stage(ce) == 0) + return 0; + } if (remove_path(path)) return -1; } return 0; } +/* add a string to a strbuf, but converting "/" to "_" */ +static void add_flattened_path(struct strbuf *out, const char *s) +{ + size_t i = out->len; + strbuf_addstr(out, s); + for (; i < out->len; i++) + if (out->buf[i] == '/') + out->buf[i] = '_'; +} + static char *unique_path(struct merge_options *o, const char *path, const char *branch) { - char *newpath = xmalloc(strlen(path) + 1 + strlen(branch) + 8 + 1); + struct strbuf newpath = STRBUF_INIT; int suffix = 0; struct stat st; - char *p = newpath + strlen(path); - strcpy(newpath, path); - *(p++) = '~'; - strcpy(p, branch); - for (; *p; ++p) - if ('/' == *p) - *p = '_'; - while (string_list_has_string(&o->current_file_set, newpath) || - string_list_has_string(&o->current_directory_set, newpath) || - lstat(newpath, &st) == 0) - sprintf(p, "_%d", suffix++); - - string_list_insert(&o->current_file_set, newpath); - return newpath; + size_t base_len; + + strbuf_addf(&newpath, "%s~", path); + add_flattened_path(&newpath, branch); + + base_len = newpath.len; + while (string_list_has_string(&o->current_file_set, newpath.buf) || + string_list_has_string(&o->current_directory_set, newpath.buf) || + lstat(newpath.buf, &st) == 0) { + strbuf_setlen(&newpath, base_len); + strbuf_addf(&newpath, "_%d", suffix++); + } + + string_list_insert(&o->current_file_set, newpath.buf); + return strbuf_detach(&newpath, NULL); } static int dir_in_way(const char *path, int check_working_copy) @@@ -712,7 -691,7 +710,7 @@@ static int make_room_for_path(struct me /* Make sure leading directories are created */ status = safe_create_leading_directories_const(path); if (status) { - if (status == -3) { + if (status == SCLD_EXISTS) { /* something else exists */ error(msg, path, _(": perhaps a D/F conflict?")); return -1; @@@ -980,10 -959,14 +978,10 @@@ merge_file_special_markers(struct merge char *side2 = NULL; struct merge_file_info mfi; - if (filename1) { - side1 = xmalloc(strlen(branch1) + strlen(filename1) + 2); - sprintf(side1, "%s:%s", branch1, filename1); - } - if (filename2) { - side2 = xmalloc(strlen(branch2) + strlen(filename2) + 2); - sprintf(side2, "%s:%s", branch2, filename2); - } + if (filename1) + side1 = xstrfmt("%s:%s", branch1, filename1); + if (filename2) + side2 = xstrfmt("%s:%s", branch2, filename2); mfi = merge_file_1(o, one, a, b, side1 ? side1 : branch1, side2 ? side2 : branch2); @@@ -1999,7 -1982,7 +1997,7 @@@ int merge_recursive_generic(struct merg const unsigned char **base_list, struct commit **result) { - int clean, index_fd; + int clean; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); struct commit *head_commit = get_ref(head, o->branch1); struct commit *next_commit = get_ref(merge, o->branch2); @@@ -2016,22 -1999,33 +2014,22 @@@ } } - index_fd = hold_locked_index(lock, 1); + hold_locked_index(lock, 1); clean = merge_recursive(o, head_commit, next_commit, ca, result); if (active_cache_changed && - (write_cache(index_fd, active_cache, active_nr) || - commit_locked_index(lock))) + write_locked_index(&the_index, lock, COMMIT_LOCK)) return error(_("Unable to write index.")); return clean ? 0 : 1; } -static int merge_recursive_config(const char *var, const char *value, void *cb) +static void merge_recursive_config(struct merge_options *o) { - struct merge_options *o = cb; - if (!strcmp(var, "merge.verbosity")) { - o->verbosity = git_config_int(var, value); - return 0; - } - if (!strcmp(var, "diff.renamelimit")) { - o->diff_rename_limit = git_config_int(var, value); - return 0; - } - if (!strcmp(var, "merge.renamelimit")) { - o->merge_rename_limit = git_config_int(var, value); - return 0; - } - return git_xmerge_config(var, value, cb); + git_config_get_int("merge.verbosity", &o->verbosity); + git_config_get_int("diff.renamelimit", &o->diff_rename_limit); + git_config_get_int("merge.renamelimit", &o->merge_rename_limit); + git_config(git_xmerge_config, NULL); } void init_merge_options(struct merge_options *o) @@@ -2042,22 -2036,23 +2040,22 @@@ o->diff_rename_limit = -1; o->merge_rename_limit = -1; o->renormalize = 0; - git_config(merge_recursive_config, o); + merge_recursive_config(o); if (getenv("GIT_MERGE_VERBOSITY")) o->verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); if (o->verbosity >= 5) o->buffer_output = 0; strbuf_init(&o->obuf, 0); - memset(&o->current_file_set, 0, sizeof(struct string_list)); - o->current_file_set.strdup_strings = 1; - memset(&o->current_directory_set, 0, sizeof(struct string_list)); - o->current_directory_set.strdup_strings = 1; - memset(&o->df_conflict_file_set, 0, sizeof(struct string_list)); - o->df_conflict_file_set.strdup_strings = 1; + string_list_init(&o->current_file_set, 1); + string_list_init(&o->current_directory_set, 1); + string_list_init(&o->df_conflict_file_set, 1); } int parse_merge_opt(struct merge_options *o, const char *s) { + const char *arg; + if (!s || !*s) return -1; if (!strcmp(s, "ours")) @@@ -2066,14 -2061,14 +2064,14 @@@ o->recursive_variant = MERGE_RECURSIVE_THEIRS; else if (!strcmp(s, "subtree")) o->subtree_shift = ""; - else if (!prefixcmp(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 (!prefixcmp(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 */ @@@ -2091,8 -2086,9 +2089,8 @@@ o->renormalize = 1; else if (!strcmp(s, "no-renormalize")) o->renormalize = 0; - else if (!prefixcmp(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 63e03b67e9,c2198a335f..31f2edef11 --- a/pretty.c +++ b/pretty.c @@@ -24,11 -24,6 +24,11 @@@ static size_t commit_formats_len static size_t commit_formats_alloc; static struct cmt_fmt_map *find_commit_format(const char *sought); +int commit_format_is_empty(enum cmit_fmt fmt) +{ + return fmt == CMIT_FMT_USERFORMAT && !*user_format; +} + static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat) { free(user_format); @@@ -45,9 -40,10 +45,9 @@@ static int git_pretty_formats_config(co const char *fmt; int i; - if (prefixcmp(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; @@@ -70,10 -66,8 +70,10 @@@ commit_format->name = xstrdup(name); commit_format->format = CMIT_FMT_USERFORMAT; - git_config_string(&fmt, var, value); - if (!prefixcmp(fmt, "format:") || !prefixcmp(fmt, "tformat:")) { + if (git_config_string(&fmt, var, value)) + return -1; + + if (starts_with(fmt, "format:") || starts_with(fmt, "tformat:")) { commit_format->is_tformat = fmt[0] == 't'; fmt = strchr(fmt, ':') + 1; } else if (strchr(fmt, '%')) @@@ -121,7 -115,7 +121,7 @@@ static struct cmt_fmt_map *find_commit_ for (i = 0; i < commit_formats_len; i++) { size_t match_len; - if (prefixcmp(commit_formats[i].name, sought)) + if (!starts_with(commit_formats[i].name, sought)) continue; match_len = strlen(commit_formats[i].name); @@@ -153,16 -147,16 +153,16 @@@ void get_commit_format(const char *arg struct cmt_fmt_map *commit_format; rev->use_terminator = 0; - if (!arg || !*arg) { + if (!arg) { rev->commit_format = CMIT_FMT_DEFAULT; return; } - if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) { + if (starts_with(arg, "format:") || starts_with(arg, "tformat:")) { save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't'); return; } - if (strchr(arg, '%')) { + if (!*arg || strchr(arg, '%')) { save_user_format(rev, arg, 1); return; } @@@ -399,22 -393,16 +399,22 @@@ static void add_rfc2047(struct strbuf * strbuf_addstr(sb, "?="); } -static const char *show_ident_date(const struct ident_split *ident, - enum date_mode mode) +const char *show_ident_date(const struct ident_split *ident, + enum date_mode mode) { unsigned long date = 0; - int tz = 0; + long tz = 0; if (ident->date_begin && ident->date_end) date = strtoul(ident->date_begin, NULL, 10); - if (ident->tz_begin && ident->tz_end) - tz = strtol(ident->tz_begin, NULL, 10); + if (date_overflows(date)) + date = 0; + else { + if (ident->tz_begin && ident->tz_end) + tz = strtol(ident->tz_begin, NULL, 10); + if (tz >= INT_MAX || tz <= INT_MIN) + tz = 0; + } return show_date(date, tz, mode); } @@@ -554,11 -542,32 +554,11 @@@ static void add_merge_info(const struc strbuf_addch(sb, '\n'); } -static char *get_header(const struct commit *commit, const char *msg, - const char *key) +static char *get_header(const char *msg, const char *key) { - int key_len = strlen(key); - const char *line = msg; - - while (line) { - const char *eol = strchr(line, '\n'), *next; - - if (line == eol) - return NULL; - if (!eol) { - warning("malformed commit (header is missing newline): %s", - sha1_to_hex(commit->object.sha1)); - eol = line + strlen(line); - next = NULL; - } else - next = eol + 1; - if (eol - line > key_len && - !strncmp(line, key, key_len) && - line[key_len] == ' ') { - return xmemdupz(line + key_len + 1, eol - line - key_len - 1); - } - line = next; - } - return NULL; + size_t len; + const char *v = find_commit_header(msg, key, &len); + return v ? xmemdupz(v, len) : NULL; } static char *replace_encoding_header(char *buf, const char *encoding) @@@ -592,22 -601,36 +592,22 @@@ 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 = - get_header(commit, msg, "encoding"); + *commit_encoding = get_header(msg, "encoding"); return msg; } - encoding = get_header(commit, msg, "encoding"); + encoding = get_header(msg, "encoding"); if (commit_encoding) *commit_encoding = encoding; use_encoding = encoding ? encoding : utf8; @@@ -624,13 -647,12 +624,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 { /* @@@ -640,8 -662,8 +640,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); } /* @@@ -660,6 -682,12 +660,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) { @@@ -717,12 -745,9 +717,12 @@@ static size_t format_person_part(struc case 'r': /* date, relative */ strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE)); return placeholder_len; - case 'i': /* date, ISO 8601 */ + case 'i': /* date, ISO 8601-like */ strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601)); return placeholder_len; + case 'I': /* date, ISO 8601 strict */ + strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601_STRICT)); + return placeholder_len; } skip: @@@ -766,7 -791,7 +766,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; @@@ -815,10 -840,10 +815,10 @@@ static void parse_commit_header(struct if (i == eol) { break; - } else if (!prefixcmp(msg + i, "author ")) { + } else if (starts_with(msg + i, "author ")) { context->author.off = i + 7; context->author.len = eol - i - 7; - } else if (!prefixcmp(msg + i, "committer ")) { + } else if (starts_with(msg + i, "committer ")) { context->committer.off = i + 10; context->committer.len = eol - i - 10; } @@@ -958,7 -983,7 +958,7 @@@ static size_t parse_color(struct strbu if (!end) return 0; - if (!prefixcmp(begin, "auto,")) { + if (starts_with(begin, "auto,")) { if (!want_color(c->pretty_ctx->color)) return end - placeholder + 1; begin += 5; @@@ -969,16 -994,16 +969,16 @@@ strbuf_addstr(sb, color); return end - placeholder + 1; } - if (!prefixcmp(placeholder + 1, "red")) { + if (starts_with(placeholder + 1, "red")) { strbuf_addstr(sb, GIT_COLOR_RED); return 4; - } else if (!prefixcmp(placeholder + 1, "green")) { + } else if (starts_with(placeholder + 1, "green")) { strbuf_addstr(sb, GIT_COLOR_GREEN); return 6; - } else if (!prefixcmp(placeholder + 1, "blue")) { + } else if (starts_with(placeholder + 1, "blue")) { strbuf_addstr(sb, GIT_COLOR_BLUE); return 5; - } else if (!prefixcmp(placeholder + 1, "reset")) { + } else if (starts_with(placeholder + 1, "reset")) { strbuf_addstr(sb, GIT_COLOR_RESET); return 6; } else @@@ -1035,11 -1060,11 +1035,11 @@@ static size_t parse_padding_placeholder end = strchr(start, ')'); if (!end || end == start) return 0; - if (!prefixcmp(start, "trunc)")) + if (starts_with(start, "trunc)")) c->truncate = trunc_right; - else if (!prefixcmp(start, "ltrunc)")) + else if (starts_with(start, "ltrunc)")) c->truncate = trunc_left; - else if (!prefixcmp(start, "mtrunc)")) + else if (starts_with(start, "mtrunc)")) c->truncate = trunc_middle; else return 0; @@@ -1064,7 -1089,7 +1064,7 @@@ static size_t format_commit_one(struct /* these are independent of the commit */ switch (placeholder[0]) { case 'C': - if (!prefixcmp(placeholder + 1, "(auto)")) { + if (starts_with(placeholder + 1, "(auto)")) { c->auto_color = 1; return 7; /* consumed 7 bytes, "C(auto)" */ } else { @@@ -1237,8 -1262,6 +1237,8 @@@ if (c->signature_check.key) strbuf_addstr(sb, c->signature_check.key); break; + default: + return 0; } return 2; } @@@ -1365,7 -1388,7 +1365,7 @@@ static size_t format_and_pad_commit(str case trunc_none: break; } - strbuf_addstr(sb, local_sb.buf); + strbuf_addbuf(sb, &local_sb); } else { int sb_len = sb->len, offset = 0; if (c->flush_type == flush_left) @@@ -1377,9 -1400,7 +1377,7 @@@ * convert it back to chars */ padding = padding - len + local_sb.len; - strbuf_grow(sb, padding); - strbuf_setlen(sb, sb_len + padding); - memset(sb->buf + sb_len, ' ', sb->len - sb_len); + strbuf_addchars(sb, ' ', padding); memcpy(sb->buf + sb_len + offset, local_sb.buf, local_sb.len); } @@@ -1478,18 -1499,13 +1476,18 @@@ void format_commit_message(const struc context.commit = commit; context.pretty_ctx = pretty_ctx; context.wrap_start = sb->len; + /* + * convert a commit message to UTF-8 first + * as far as 'format_commit_item' assumes it in UTF-8 + */ context.message = logmsg_reencode(commit, &context.commit_encoding, - output_enc); + utf8); strbuf_expand(sb, format, format_commit_item, &context); rewrap_message_tail(sb, &context, 0, 0, 0); + /* then convert a commit message to an actual output encoding */ if (output_enc) { if (same_encoding(utf8, output_enc)) output_enc = NULL; @@@ -1508,7 -1524,9 +1506,7 @@@ } free(context.commit_encoding); - logmsg_free(context.message, commit); - free(context.signature_check.gpg_output); - free(context.signature_check.signer); + unuse_commit_buffer(commit, context.message); } static void pp_header(struct pretty_print_context *pp, @@@ -1536,14 -1554,19 +1534,14 @@@ continue; } - if (!prefixcmp(line, "parent ")) { + if (starts_with(line, "parent ")) { if (linelen != 48) die("bad parent line in commit"); continue; } if (!parents_shown) { - struct commit_list *parent; - int num; - for (parent = commit->parents, num = 0; - parent; - parent = parent->next, num++) - ; + unsigned num = commit_list_count(commit->parents); /* with enough slop */ strbuf_grow(sb, num * 50 + 20); add_merge_info(pp, sb, commit); @@@ -1555,11 -1578,11 +1553,11 @@@ * FULL shows both authors but not dates. * FULLER shows both authors and dates. */ - if (!prefixcmp(line, "author ")) { + if (starts_with(line, "author ")) { strbuf_grow(sb, linelen + 80); pp_user_info(pp, "Author", sb, line + 7, encoding); } - if (!prefixcmp(line, "committer ") && + if (starts_with(line, "committer ") && (pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) { strbuf_grow(sb, linelen + 80); pp_user_info(pp, "Commit", sb, line + 10, encoding); @@@ -1654,10 -1677,8 +1652,8 @@@ void pp_remainder(struct pretty_print_c first = 0; strbuf_grow(sb, linelen + indent + 20); - if (indent) { - memset(sb->buf + sb->len, ' ', indent); - strbuf_setlen(sb, sb->len + indent); - } + if (indent) + strbuf_addchars(sb, ' ', indent); strbuf_add(sb, line, linelen); strbuf_addch(sb, '\n'); } @@@ -1670,7 -1691,7 +1666,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; @@@ -1737,7 -1758,7 +1733,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 strbuf.c index 4d3144308f,5e44cf9204..0346e74a47 --- a/strbuf.c +++ b/strbuf.c @@@ -1,14 -1,22 +1,14 @@@ #include "cache.h" #include "refs.h" +#include "utf8.h" -int prefixcmp(const char *str, const char *prefix) +int starts_with(const char *str, const char *prefix) { for (; ; str++, prefix++) if (!*prefix) - return 0; + return 1; else if (*str != *prefix) - return (unsigned char)*prefix - (unsigned char)*str; -} - -int suffixcmp(const char *str, const char *suffix) -{ - int len = strlen(str), suflen = strlen(suffix); - if (len < suflen) - return -1; - else - return strcmp(str + len - suflen, suffix); + return 0; } /* @@@ -70,8 -78,15 +70,8 @@@ void strbuf_grow(struct strbuf *sb, siz void strbuf_trim(struct strbuf *sb) { - char *b = sb->buf; - while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) - sb->len--; - while (sb->len > 0 && isspace(*b)) { - b++; - sb->len--; - } - memmove(sb->buf, b, sb->len); - sb->buf[sb->len] = '\0'; + strbuf_rtrim(sb); + strbuf_ltrim(sb); } void strbuf_rtrim(struct strbuf *sb) { @@@ -91,29 -106,6 +91,29 @@@ void strbuf_ltrim(struct strbuf *sb sb->buf[sb->len] = '\0'; } +int strbuf_reencode(struct strbuf *sb, const char *from, const char *to) +{ + char *out; + int len; + + if (same_encoding(from, to)) + return 0; + + out = reencode_string_len(sb->buf, sb->len, to, from, &len); + if (!out) + return -1; + + strbuf_attach(sb, out, len, len); + return 0; +} + +void strbuf_tolower(struct strbuf *sb) +{ + char *p = sb->buf, *end = sb->buf + sb->len; + for (; p < end; p++) + *p = tolower(*p); +} + struct strbuf **strbuf_split_buf(const char *str, size_t slen, int terminator, int max) { @@@ -204,6 -196,13 +204,13 @@@ void strbuf_adddup(struct strbuf *sb, s strbuf_setlen(sb, sb->len + len); } + void strbuf_addchars(struct strbuf *sb, int c, size_t n) + { + strbuf_grow(sb, n); + memset(sb->buf + sb->len, c, n); + strbuf_setlen(sb, sb->len + n); + } + void strbuf_addf(struct strbuf *sb, const char *fmt, ...) { va_list ap; @@@ -406,27 -405,6 +413,27 @@@ int strbuf_readlink(struct strbuf *sb, return -1; } +int strbuf_getcwd(struct strbuf *sb) +{ + size_t oldalloc = sb->alloc; + size_t guessed_len = 128; + + for (;; guessed_len *= 2) { + strbuf_grow(sb, guessed_len); + if (getcwd(sb->buf, sb->alloc)) { + strbuf_setlen(sb, strlen(sb->buf)); + return 0; + } + if (errno != ERANGE) + break; + } + if (oldalloc == 0) + strbuf_release(sb); + else + strbuf_reset(sb); + return -1; +} + int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) { int ch; @@@ -576,31 -554,6 +583,31 @@@ void strbuf_humanise_bytes(struct strbu } } +void strbuf_add_absolute_path(struct strbuf *sb, const char *path) +{ + if (!*path) + die("The empty string is not a valid path"); + if (!is_absolute_path(path)) { + struct stat cwd_stat, pwd_stat; + size_t orig_len = sb->len; + char *cwd = xgetcwd(); + char *pwd = getenv("PWD"); + if (pwd && strcmp(pwd, cwd) && + !stat(cwd, &cwd_stat) && + (cwd_stat.st_dev || cwd_stat.st_ino) && + !stat(pwd, &pwd_stat) && + pwd_stat.st_dev == cwd_stat.st_dev && + pwd_stat.st_ino == cwd_stat.st_ino) + strbuf_addstr(sb, pwd); + else + strbuf_addstr(sb, cwd); + if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1])) + strbuf_addch(sb, '/'); + free(cwd); + } + strbuf_addstr(sb, path); +} + int printf_ln(const char *fmt, ...) { int ret; @@@ -624,35 -577,3 +631,35 @@@ int fprintf_ln(FILE *fp, const char *fm return -1; return ret + 1; } + +char *xstrdup_tolower(const char *string) +{ + char *result; + size_t len, i; + + len = strlen(string); + result = xmalloc(len + 1); + for (i = 0; i < len; i++) + result[i] = tolower(string[i]); + result[i] = '\0'; + return result; +} + +char *xstrvfmt(const char *fmt, va_list ap) +{ + struct strbuf buf = STRBUF_INIT; + strbuf_vaddf(&buf, fmt, ap); + return strbuf_detach(&buf, NULL); +} + +char *xstrfmt(const char *fmt, ...) +{ + va_list ap; + char *ret; + + va_start(ap, fmt); + ret = xstrvfmt(fmt, ap); + va_end(ap); + + return ret; +} diff --combined strbuf.h index 7bdc1da507,2c34753a68..652b6c432b --- a/strbuf.h +++ b/strbuf.h @@@ -17,23 -17,20 +17,23 @@@ extern void strbuf_init(struct strbuf * extern void strbuf_release(struct strbuf *); extern char *strbuf_detach(struct strbuf *, size_t *); extern void strbuf_attach(struct strbuf *, void *, size_t, size_t); -static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) { +static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) +{ struct strbuf tmp = *a; *a = *b; *b = tmp; } /*----- strbuf size related -----*/ -static inline size_t strbuf_avail(const struct strbuf *sb) { +static inline size_t strbuf_avail(const struct strbuf *sb) +{ return sb->alloc ? sb->alloc - sb->len - 1 : 0; } extern void strbuf_grow(struct strbuf *, size_t); -static inline void strbuf_setlen(struct strbuf *sb, size_t len) { +static inline void strbuf_setlen(struct strbuf *sb, size_t len) +{ if (len > (sb->alloc ? sb->alloc - 1 : 0)) die("BUG: strbuf_setlen() beyond buffer"); sb->len = len; @@@ -45,19 -42,8 +45,19 @@@ extern void strbuf_trim(struct strbuf *); extern void strbuf_rtrim(struct strbuf *); extern void strbuf_ltrim(struct strbuf *); +extern int strbuf_reencode(struct strbuf *sb, const char *from, const char *to); +extern void strbuf_tolower(struct strbuf *sb); extern int strbuf_cmp(const struct strbuf *, const struct strbuf *); +static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix) +{ + if (strip_suffix_mem(sb->buf, &sb->len, suffix)) { + strbuf_setlen(sb, sb->len); + return 1; + } else + return 0; +} + /* * Split str (of length slen) at the specified terminator character. * Return a null-terminated array of pointers to strbuf objects @@@ -111,8 -97,7 +111,8 @@@ static inline struct strbuf **strbuf_sp extern void strbuf_list_free(struct strbuf **); /*----- add data in your buffer -----*/ -static inline void strbuf_addch(struct strbuf *sb, int c) { +static inline void strbuf_addch(struct strbuf *sb, int c) +{ strbuf_grow(sb, 1); sb->buf[sb->len++] = c; sb->buf[sb->len] = '\0'; @@@ -128,16 -113,15 +128,17 @@@ extern void strbuf_splice(struct strbu extern void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size); extern void strbuf_add(struct strbuf *, const void *, size_t); -static inline void strbuf_addstr(struct strbuf *sb, const char *s) { +static inline void strbuf_addstr(struct strbuf *sb, const char *s) +{ strbuf_add(sb, s, strlen(s)); } -static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) { +static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) +{ strbuf_grow(sb, sb2->len); strbuf_add(sb, sb2->buf, sb2->len); } extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len); + extern void strbuf_addchars(struct strbuf *sb, int c, size_t n); typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context); extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context); @@@ -174,7 -158,6 +175,7 @@@ extern size_t strbuf_fread(struct strbu extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint); extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint); +extern int strbuf_getcwd(struct strbuf *sb); extern int strbuf_getwholeline(struct strbuf *, FILE *, int); extern int strbuf_getline(struct strbuf *, FILE *, int); @@@ -190,22 -173,9 +191,22 @@@ extern void strbuf_addstr_urlencode(str int reserved); extern void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes); +extern void strbuf_add_absolute_path(struct strbuf *sb, const char *path); + __attribute__((format (printf,1,2))) extern int printf_ln(const char *fmt, ...); __attribute__((format (printf,2,3))) extern int fprintf_ln(FILE *fp, const char *fmt, ...); +char *xstrdup_tolower(const char *); + +/* + * Create a newly allocated string using printf format. You can do this easily + * with a strbuf, but this provides a shortcut to save a few lines. + */ +__attribute__((format (printf, 1, 0))) +char *xstrvfmt(const char *fmt, va_list ap); +__attribute__((format (printf, 1, 2))) +char *xstrfmt(const char *fmt, ...); + #endif /* STRBUF_H */ diff --combined utf8.c index 401a6a509e,c55f3ba0bc..4541777949 --- a/utf8.c +++ b/utf8.c @@@ -5,8 -5,8 +5,8 @@@ /* This code is originally from http://www.cl.cam.ac.uk/~mgk25/ucs/ */ struct interval { - int first; - int last; + ucs_char_t first; + ucs_char_t last; }; size_t display_mode_esc_sequence_len(const char *s) @@@ -80,8 -80,53 +80,8 @@@ static int git_wcwidth(ucs_char_t ch { /* * Sorted list of non-overlapping intervals of non-spacing characters, - * generated by - * "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c". */ - static const struct interval combining[] = { - { 0x0300, 0x0357 }, { 0x035D, 0x036F }, { 0x0483, 0x0486 }, - { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 }, - { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, - { 0x05C4, 0x05C4 }, { 0x0600, 0x0603 }, { 0x0610, 0x0615 }, - { 0x064B, 0x0658 }, { 0x0670, 0x0670 }, { 0x06D6, 0x06E4 }, - { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x070F, 0x070F }, - { 0x0711, 0x0711 }, { 0x0730, 0x074A }, { 0x07A6, 0x07B0 }, - { 0x0901, 0x0902 }, { 0x093C, 0x093C }, { 0x0941, 0x0948 }, - { 0x094D, 0x094D }, { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, - { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, - { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, - { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, - { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, - { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, - { 0x0ACD, 0x0ACD }, { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, - { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, - { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, - { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, - { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, - { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, - { 0x0CCC, 0x0CCD }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, - { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, - { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, - { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, - { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, - { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, - { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, - { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, - { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, - { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x1712, 0x1714 }, - { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, { 0x1772, 0x1773 }, - { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 }, - { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, { 0x180B, 0x180D }, - { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, { 0x1927, 0x1928 }, - { 0x1932, 0x1932 }, { 0x1939, 0x193B }, { 0x200B, 0x200F }, - { 0x202A, 0x202E }, { 0x2060, 0x2063 }, { 0x206A, 0x206F }, - { 0x20D0, 0x20EA }, { 0x302A, 0x302F }, { 0x3099, 0x309A }, - { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE23 }, - { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, { 0x1D167, 0x1D169 }, - { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, - { 0x1D1AA, 0x1D1AD }, { 0xE0001, 0xE0001 }, - { 0xE0020, 0xE007F }, { 0xE0100, 0xE01EF } - }; +#include "unicode_width.h" /* test for 8-bit control characters */ if (ch == 0) @@@ -90,16 -135,34 +90,16 @@@ return -1; /* binary search in table of non-spacing characters */ - if (bisearch(ch, combining, sizeof(combining) + if (bisearch(ch, zero_width, sizeof(zero_width) / sizeof(struct interval) - 1)) return 0; - /* - * If we arrive here, ch is neither a combining nor a C0/C1 - * control character. - */ + /* binary search in table of double width characters */ + if (bisearch(ch, double_width, sizeof(double_width) + / sizeof(struct interval) - 1)) + return 2; - return 1 + - (ch >= 0x1100 && - /* Hangul Jamo init. consonants */ - (ch <= 0x115f || - ch == 0x2329 || ch == 0x232a || - /* CJK ... Yi */ - (ch >= 0x2e80 && ch <= 0xa4cf && - ch != 0x303f) || - /* Hangul Syllables */ - (ch >= 0xac00 && ch <= 0xd7a3) || - /* CJK Compatibility Ideographs */ - (ch >= 0xf900 && ch <= 0xfaff) || - /* CJK Compatibility Forms */ - (ch >= 0xfe30 && ch <= 0xfe6f) || - /* Fullwidth Forms */ - (ch >= 0xff00 && ch <= 0xff60) || - (ch >= 0xffe0 && ch <= 0xffe6) || - (ch >= 0x20000 && ch <= 0x2fffd) || - (ch >= 0x30000 && ch <= 0x3fffd))); + return 1; } /* @@@ -239,13 -302,6 +239,6 @@@ int is_utf8(const char *text return 1; } - static void strbuf_addchars(struct strbuf *sb, int c, size_t n) - { - strbuf_grow(sb, n); - memset(sb->buf + sb->len, c, n); - strbuf_setlen(sb, sb->len + n); - } - static void strbuf_add_indented_text(struct strbuf *buf, const char *text, int indent, int indent2) { @@@ -382,9 -438,6 +375,9 @@@ void strbuf_utf8_replace(struct strbuf dst += n; } + if (src >= end) + break; + old = src; n = utf8_width((const char**)&src, NULL); if (!src) /* broken utf-8, do nothing */ @@@ -469,7 -522,7 +462,7 @@@ char *reencode_string_iconv(const char while (1) { size_t cnt = iconv(conv, &cp, &insz, &outpos, &outsz); - if (cnt == -1) { + if (cnt == (size_t) -1) { size_t sofar; if (errno != E2BIG) { free(out);