X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=config.c;h=eebce8c7e09393fa8756230e483965674b9afbdf;hb=dce1e0b6daaa872a3b88724d9aa1b087c95e8754;hp=d12e0f34f1308a294e8f0eba13d7cb7d7c0cb640;hpb=9ccf3e9b22b6843892319b189fd7aed37c451420;p=thirdparty%2Fgit.git diff --git a/config.c b/config.c index d12e0f34f1..eebce8c7e0 100644 --- a/config.c +++ b/config.c @@ -817,7 +817,8 @@ static int get_next_char(struct config_source *cs) static char *parse_value(struct config_source *cs) { - int quote = 0, comment = 0, space = 0; + int quote = 0, comment = 0; + size_t trim_len = 0; strbuf_reset(&cs->value); for (;;) { @@ -827,13 +828,17 @@ static char *parse_value(struct config_source *cs) cs->linenr--; return NULL; } + if (trim_len) + strbuf_setlen(&cs->value, trim_len); return cs->value.buf; } if (comment) continue; if (isspace(c) && !quote) { + if (!trim_len) + trim_len = cs->value.len; if (cs->value.len) - space++; + strbuf_addch(&cs->value, c); continue; } if (!quote) { @@ -842,8 +847,8 @@ static char *parse_value(struct config_source *cs) continue; } } - for (; space; space--) - strbuf_addch(&cs->value, ' '); + if (trim_len) + trim_len = 0; if (c == '\\') { c = get_next_char(cs); switch (c) { @@ -869,7 +874,7 @@ static char *parse_value(struct config_source *cs) continue; } if (c == '"') { - quote = 1-quote; + quote = 1 - quote; continue; } strbuf_addch(&cs->value, c); @@ -3004,6 +3009,7 @@ static ssize_t write_section(int fd, const char *key, } static ssize_t write_pair(int fd, const char *key, const char *value, + const char *comment, const struct config_store_data *store) { int i; @@ -3044,7 +3050,11 @@ static ssize_t write_pair(int fd, const char *key, const char *value, strbuf_addch(&sb, value[i]); break; } - strbuf_addf(&sb, "%s\n", quote); + + if (comment) + strbuf_addf(&sb, "%s%s\n", quote, comment); + else + strbuf_addf(&sb, "%s\n", quote); ret = write_in_full(fd, sb.buf, sb.len); strbuf_release(&sb); @@ -3133,9 +3143,9 @@ static void maybe_remove_section(struct config_store_data *store, } int git_config_set_in_file_gently(const char *config_filename, - const char *key, const char *value) + const char *key, const char *comment, const char *value) { - return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0); + return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, comment, 0); } void git_config_set_in_file(const char *config_filename, @@ -3156,7 +3166,7 @@ int repo_config_set_worktree_gently(struct repository *r, if (r->repository_format_worktree_config) { char *file = repo_git_path(r, "config.worktree"); int ret = git_config_set_multivar_in_file_gently( - file, key, value, NULL, 0); + file, key, value, NULL, NULL, 0); free(file); return ret; } @@ -3170,6 +3180,62 @@ void git_config_set(const char *key, const char *value) trace2_cmd_set_config(key, value); } +/* + * The ownership rule is that the caller will own the string + * if it receives a piece of memory different from what it passed + * as the parameter. + */ +const char *git_config_prepare_comment_string(const char *comment) +{ + size_t leading_blanks; + + if (!comment) + return NULL; + + if (strchr(comment, '\n')) + die(_("no multi-line comment allowed: '%s'"), comment); + + /* + * If it begins with one or more leading whitespace characters + * followed by '#", the comment string is used as-is. + * + * If it begins with '#', a SP is inserted between the comment + * and the value the comment is about. + * + * Otherwise, the value is followed by a SP followed by '#' + * followed by SP and then the comment string comes. + */ + + leading_blanks = strspn(comment, " \t"); + if (leading_blanks && comment[leading_blanks] == '#') + ; /* use it as-is */ + else if (comment[0] == '#') + comment = xstrfmt(" %s", comment); + else + comment = xstrfmt(" # %s", comment); + + return comment; +} + +static void validate_comment_string(const char *comment) +{ + size_t leading_blanks; + + if (!comment) + return; + /* + * The front-end must have massaged the comment string + * properly before calling us. + */ + if (strchr(comment, '\n')) + BUG("multi-line comments are not permitted: '%s'", comment); + + leading_blanks = strspn(comment, " \t"); + if (!leading_blanks || comment[leading_blanks] != '#') + BUG("comment must begin with one or more SP followed by '#': '%s'", + comment); +} + /* * If value==NULL, unset in (remove from) config, * if value_pattern!=NULL, disregard key/value pairs where value does not match. @@ -3198,6 +3264,7 @@ void git_config_set(const char *key, const char *value) int git_config_set_multivar_in_file_gently(const char *config_filename, const char *key, const char *value, const char *value_pattern, + const char *comment, unsigned flags) { int fd = -1, in_fd = -1; @@ -3208,6 +3275,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, size_t contents_sz; struct config_store_data store = CONFIG_STORE_INIT; + validate_comment_string(comment); + /* parse-key returns negative; flip the sign to feed exit(3) */ ret = 0 - git_config_parse_key(key, &store.key, &store.baselen); if (ret) @@ -3248,7 +3317,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, free(store.key); store.key = xstrdup(key); if (write_section(fd, key, &store) < 0 || - write_pair(fd, key, value, &store) < 0) + write_pair(fd, key, value, comment, &store) < 0) goto write_err_out; } else { struct stat st; @@ -3402,7 +3471,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, if (write_section(fd, key, &store) < 0) goto write_err_out; } - if (write_pair(fd, key, value, &store) < 0) + if (write_pair(fd, key, value, comment, &store) < 0) goto write_err_out; } @@ -3447,7 +3516,7 @@ void git_config_set_multivar_in_file(const char *config_filename, const char *value_pattern, unsigned flags) { if (!git_config_set_multivar_in_file_gently(config_filename, key, value, - value_pattern, flags)) + value_pattern, NULL, flags)) return; if (value) die(_("could not set '%s' to '%s'"), key, value); @@ -3470,7 +3539,7 @@ int repo_config_set_multivar_gently(struct repository *r, const char *key, int res = git_config_set_multivar_in_file_gently(file, key, value, value_pattern, - flags); + NULL, flags); free(file); return res; }