зеркало из https://github.com/microsoft/git.git
Merge branch 'rs/strbuf-expand-step'
Code clean-up around strbuf_expand() API. * rs/strbuf-expand-step: strbuf: simplify strbuf_expand_literal_cb() replace strbuf_expand() with strbuf_expand_step() replace strbuf_expand_dict_cb() with strbuf_expand_step() strbuf: factor out strbuf_expand_step() pretty: factor out expand_separator()
This commit is contained in:
Коммит
da269af920
|
@ -366,17 +366,8 @@ static const char *quote_literal_for_format(const char *s)
|
||||||
static struct strbuf buf = STRBUF_INIT;
|
static struct strbuf buf = STRBUF_INIT;
|
||||||
|
|
||||||
strbuf_reset(&buf);
|
strbuf_reset(&buf);
|
||||||
while (*s) {
|
while (strbuf_expand_step(&buf, &s))
|
||||||
const char *ep = strchrnul(s, '%');
|
strbuf_addstr(&buf, "%%");
|
||||||
if (s < ep)
|
|
||||||
strbuf_add(&buf, s, ep - s);
|
|
||||||
if (*ep == '%') {
|
|
||||||
strbuf_addstr(&buf, "%%");
|
|
||||||
s = ep + 1;
|
|
||||||
} else {
|
|
||||||
s = ep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf.buf;
|
return buf.buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -309,10 +309,8 @@ static int is_atom(const char *atom, const char *s, int slen)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void expand_atom(struct strbuf *sb, const char *atom, int len,
|
static void expand_atom(struct strbuf *sb, const char *atom, int len,
|
||||||
void *vdata)
|
struct expand_data *data)
|
||||||
{
|
{
|
||||||
struct expand_data *data = vdata;
|
|
||||||
|
|
||||||
if (is_atom("objectname", atom, len)) {
|
if (is_atom("objectname", atom, len)) {
|
||||||
if (!data->mark_query)
|
if (!data->mark_query)
|
||||||
strbuf_addstr(sb, oid_to_hex(&data->oid));
|
strbuf_addstr(sb, oid_to_hex(&data->oid));
|
||||||
|
@ -346,19 +344,21 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
|
||||||
die("unknown format element: %.*s", len, atom);
|
die("unknown format element: %.*s", len, atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t expand_format(struct strbuf *sb, const char *start, void *data)
|
static void expand_format(struct strbuf *sb, const char *start,
|
||||||
|
struct expand_data *data)
|
||||||
{
|
{
|
||||||
const char *end;
|
while (strbuf_expand_step(sb, &start)) {
|
||||||
|
const char *end;
|
||||||
|
|
||||||
if (*start != '(')
|
if (skip_prefix(start, "%", &start) || *start != '(')
|
||||||
return 0;
|
strbuf_addch(sb, '%');
|
||||||
end = strchr(start + 1, ')');
|
else if (!(end = strchr(start + 1, ')')))
|
||||||
if (!end)
|
die("format element '%s' does not end in ')'", start);
|
||||||
die("format element '%s' does not end in ')'", start);
|
else {
|
||||||
|
expand_atom(sb, start + 1, end - start - 1, data);
|
||||||
expand_atom(sb, start + 1, end - start - 1, data);
|
start = end + 1;
|
||||||
|
}
|
||||||
return end - start + 1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void batch_write(struct batch_options *opt, const void *data, int len)
|
static void batch_write(struct batch_options *opt, const void *data, int len)
|
||||||
|
@ -495,7 +495,7 @@ static void batch_object_write(const char *obj_name,
|
||||||
if (!opt->format) {
|
if (!opt->format) {
|
||||||
print_default_format(scratch, data, opt);
|
print_default_format(scratch, data, opt);
|
||||||
} else {
|
} else {
|
||||||
strbuf_expand(scratch, opt->format, expand_format, data);
|
expand_format(scratch, opt->format, data);
|
||||||
strbuf_addch(scratch, opt->output_delim);
|
strbuf_addch(scratch, opt->output_delim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -773,9 +773,8 @@ static int batch_objects(struct batch_options *opt)
|
||||||
*/
|
*/
|
||||||
memset(&data, 0, sizeof(data));
|
memset(&data, 0, sizeof(data));
|
||||||
data.mark_query = 1;
|
data.mark_query = 1;
|
||||||
strbuf_expand(&output,
|
expand_format(&output,
|
||||||
opt->format ? opt->format : DEFAULT_FORMAT,
|
opt->format ? opt->format : DEFAULT_FORMAT,
|
||||||
expand_format,
|
|
||||||
&data);
|
&data);
|
||||||
data.mark_query = 0;
|
data.mark_query = 0;
|
||||||
strbuf_release(&output);
|
strbuf_release(&output);
|
||||||
|
|
|
@ -264,74 +264,57 @@ static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
|
||||||
strbuf_addstr(line, "-");
|
strbuf_addstr(line, "-");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct show_index_data {
|
|
||||||
const char *pathname;
|
|
||||||
struct index_state *istate;
|
|
||||||
const struct cache_entry *ce;
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t expand_show_index(struct strbuf *sb, const char *start,
|
|
||||||
void *context)
|
|
||||||
{
|
|
||||||
struct show_index_data *data = context;
|
|
||||||
const char *end;
|
|
||||||
const char *p;
|
|
||||||
size_t len = strbuf_expand_literal_cb(sb, start, NULL);
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
return len;
|
|
||||||
if (*start != '(')
|
|
||||||
die(_("bad ls-files format: element '%s' "
|
|
||||||
"does not start with '('"), start);
|
|
||||||
|
|
||||||
end = strchr(start + 1, ')');
|
|
||||||
if (!end)
|
|
||||||
die(_("bad ls-files format: element '%s' "
|
|
||||||
"does not end in ')'"), start);
|
|
||||||
|
|
||||||
len = end - start + 1;
|
|
||||||
if (skip_prefix(start, "(objectmode)", &p))
|
|
||||||
strbuf_addf(sb, "%06o", data->ce->ce_mode);
|
|
||||||
else if (skip_prefix(start, "(objectname)", &p))
|
|
||||||
strbuf_add_unique_abbrev(sb, &data->ce->oid, abbrev);
|
|
||||||
else if (skip_prefix(start, "(objecttype)", &p))
|
|
||||||
strbuf_addstr(sb, type_name(object_type(data->ce->ce_mode)));
|
|
||||||
else if (skip_prefix(start, "(objectsize:padded)", &p))
|
|
||||||
expand_objectsize(sb, &data->ce->oid, object_type(data->ce->ce_mode), 1);
|
|
||||||
else if (skip_prefix(start, "(objectsize)", &p))
|
|
||||||
expand_objectsize(sb, &data->ce->oid, object_type(data->ce->ce_mode), 0);
|
|
||||||
else if (skip_prefix(start, "(stage)", &p))
|
|
||||||
strbuf_addf(sb, "%d", ce_stage(data->ce));
|
|
||||||
else if (skip_prefix(start, "(eolinfo:index)", &p))
|
|
||||||
strbuf_addstr(sb, S_ISREG(data->ce->ce_mode) ?
|
|
||||||
get_cached_convert_stats_ascii(data->istate,
|
|
||||||
data->ce->name) : "");
|
|
||||||
else if (skip_prefix(start, "(eolinfo:worktree)", &p))
|
|
||||||
strbuf_addstr(sb, !lstat(data->pathname, &st) &&
|
|
||||||
S_ISREG(st.st_mode) ?
|
|
||||||
get_wt_convert_stats_ascii(data->pathname) : "");
|
|
||||||
else if (skip_prefix(start, "(eolattr)", &p))
|
|
||||||
strbuf_addstr(sb, get_convert_attr_ascii(data->istate,
|
|
||||||
data->pathname));
|
|
||||||
else if (skip_prefix(start, "(path)", &p))
|
|
||||||
write_name_to_buf(sb, data->pathname);
|
|
||||||
else
|
|
||||||
die(_("bad ls-files format: %%%.*s"), (int)len, start);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
|
static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
|
||||||
const char *format, const char *fullname) {
|
const char *format, const char *fullname) {
|
||||||
struct show_index_data data = {
|
|
||||||
.pathname = fullname,
|
|
||||||
.istate = repo->index,
|
|
||||||
.ce = ce,
|
|
||||||
};
|
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
|
||||||
strbuf_expand(&sb, format, expand_show_index, &data);
|
while (strbuf_expand_step(&sb, &format)) {
|
||||||
|
const char *end;
|
||||||
|
size_t len;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (skip_prefix(format, "%", &format))
|
||||||
|
strbuf_addch(&sb, '%');
|
||||||
|
else if ((len = strbuf_expand_literal(&sb, format)))
|
||||||
|
format += len;
|
||||||
|
else if (*format != '(')
|
||||||
|
die(_("bad ls-files format: element '%s' "
|
||||||
|
"does not start with '('"), format);
|
||||||
|
else if (!(end = strchr(format + 1, ')')))
|
||||||
|
die(_("bad ls-files format: element '%s' "
|
||||||
|
"does not end in ')'"), format);
|
||||||
|
else if (skip_prefix(format, "(objectmode)", &format))
|
||||||
|
strbuf_addf(&sb, "%06o", ce->ce_mode);
|
||||||
|
else if (skip_prefix(format, "(objectname)", &format))
|
||||||
|
strbuf_add_unique_abbrev(&sb, &ce->oid, abbrev);
|
||||||
|
else if (skip_prefix(format, "(objecttype)", &format))
|
||||||
|
strbuf_addstr(&sb, type_name(object_type(ce->ce_mode)));
|
||||||
|
else if (skip_prefix(format, "(objectsize:padded)", &format))
|
||||||
|
expand_objectsize(&sb, &ce->oid,
|
||||||
|
object_type(ce->ce_mode), 1);
|
||||||
|
else if (skip_prefix(format, "(objectsize)", &format))
|
||||||
|
expand_objectsize(&sb, &ce->oid,
|
||||||
|
object_type(ce->ce_mode), 0);
|
||||||
|
else if (skip_prefix(format, "(stage)", &format))
|
||||||
|
strbuf_addf(&sb, "%d", ce_stage(ce));
|
||||||
|
else if (skip_prefix(format, "(eolinfo:index)", &format))
|
||||||
|
strbuf_addstr(&sb, S_ISREG(ce->ce_mode) ?
|
||||||
|
get_cached_convert_stats_ascii(repo->index,
|
||||||
|
ce->name) : "");
|
||||||
|
else if (skip_prefix(format, "(eolinfo:worktree)", &format))
|
||||||
|
strbuf_addstr(&sb, !lstat(fullname, &st) &&
|
||||||
|
S_ISREG(st.st_mode) ?
|
||||||
|
get_wt_convert_stats_ascii(fullname) : "");
|
||||||
|
else if (skip_prefix(format, "(eolattr)", &format))
|
||||||
|
strbuf_addstr(&sb, get_convert_attr_ascii(repo->index,
|
||||||
|
fullname));
|
||||||
|
else if (skip_prefix(format, "(path)", &format))
|
||||||
|
write_name_to_buf(&sb, fullname);
|
||||||
|
else
|
||||||
|
die(_("bad ls-files format: %%%.*s"),
|
||||||
|
(int)(end - format + 1), format);
|
||||||
|
}
|
||||||
strbuf_addch(&sb, line_terminator);
|
strbuf_addch(&sb, line_terminator);
|
||||||
fwrite(sb.buf, sb.len, 1, stdout);
|
fwrite(sb.buf, sb.len, 1, stdout);
|
||||||
strbuf_release(&sb);
|
strbuf_release(&sb);
|
||||||
|
|
|
@ -55,63 +55,6 @@ struct ls_tree_options {
|
||||||
const char *format;
|
const char *format;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct show_tree_data {
|
|
||||||
struct ls_tree_options *options;
|
|
||||||
unsigned mode;
|
|
||||||
enum object_type type;
|
|
||||||
const struct object_id *oid;
|
|
||||||
const char *pathname;
|
|
||||||
struct strbuf *base;
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t expand_show_tree(struct strbuf *sb, const char *start,
|
|
||||||
void *context)
|
|
||||||
{
|
|
||||||
struct show_tree_data *data = context;
|
|
||||||
struct ls_tree_options *options = data->options;
|
|
||||||
const char *end;
|
|
||||||
const char *p;
|
|
||||||
unsigned int errlen;
|
|
||||||
size_t len = strbuf_expand_literal_cb(sb, start, NULL);
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
return len;
|
|
||||||
if (*start != '(')
|
|
||||||
die(_("bad ls-tree format: element '%s' does not start with '('"), start);
|
|
||||||
|
|
||||||
end = strchr(start + 1, ')');
|
|
||||||
if (!end)
|
|
||||||
die(_("bad ls-tree format: element '%s' does not end in ')'"), start);
|
|
||||||
|
|
||||||
len = end - start + 1;
|
|
||||||
if (skip_prefix(start, "(objectmode)", &p)) {
|
|
||||||
strbuf_addf(sb, "%06o", data->mode);
|
|
||||||
} else if (skip_prefix(start, "(objecttype)", &p)) {
|
|
||||||
strbuf_addstr(sb, type_name(data->type));
|
|
||||||
} else if (skip_prefix(start, "(objectsize:padded)", &p)) {
|
|
||||||
expand_objectsize(sb, data->oid, data->type, 1);
|
|
||||||
} else if (skip_prefix(start, "(objectsize)", &p)) {
|
|
||||||
expand_objectsize(sb, data->oid, data->type, 0);
|
|
||||||
} else if (skip_prefix(start, "(objectname)", &p)) {
|
|
||||||
strbuf_add_unique_abbrev(sb, data->oid, options->abbrev);
|
|
||||||
} else if (skip_prefix(start, "(path)", &p)) {
|
|
||||||
const char *name = data->base->buf;
|
|
||||||
const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
|
|
||||||
struct strbuf sbuf = STRBUF_INIT;
|
|
||||||
size_t baselen = data->base->len;
|
|
||||||
|
|
||||||
strbuf_addstr(data->base, data->pathname);
|
|
||||||
name = relative_path(data->base->buf, prefix, &sbuf);
|
|
||||||
quote_c_style(name, sb, NULL, 0);
|
|
||||||
strbuf_setlen(data->base, baselen);
|
|
||||||
strbuf_release(&sbuf);
|
|
||||||
} else {
|
|
||||||
errlen = (unsigned long)len;
|
|
||||||
die(_("bad ls-tree format: %%%.*s"), errlen, start);
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int show_recursive(struct ls_tree_options *options, const char *base,
|
static int show_recursive(struct ls_tree_options *options, const char *base,
|
||||||
size_t baselen, const char *pathname)
|
size_t baselen, const char *pathname)
|
||||||
{
|
{
|
||||||
|
@ -150,14 +93,7 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
|
||||||
int recurse = 0;
|
int recurse = 0;
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
enum object_type type = object_type(mode);
|
enum object_type type = object_type(mode);
|
||||||
struct show_tree_data cb_data = {
|
const char *format = options->format;
|
||||||
.options = options,
|
|
||||||
.mode = mode,
|
|
||||||
.type = type,
|
|
||||||
.oid = oid,
|
|
||||||
.pathname = pathname,
|
|
||||||
.base = base,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
|
if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
|
||||||
recurse = READ_TREE_RECURSIVE;
|
recurse = READ_TREE_RECURSIVE;
|
||||||
|
@ -166,7 +102,46 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
|
||||||
if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
|
if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
strbuf_expand(&sb, options->format, expand_show_tree, &cb_data);
|
while (strbuf_expand_step(&sb, &format)) {
|
||||||
|
const char *end;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (skip_prefix(format, "%", &format))
|
||||||
|
strbuf_addch(&sb, '%');
|
||||||
|
else if ((len = strbuf_expand_literal(&sb, format)))
|
||||||
|
format += len;
|
||||||
|
else if (*format != '(')
|
||||||
|
die(_("bad ls-tree format: element '%s' "
|
||||||
|
"does not start with '('"), format);
|
||||||
|
else if (!(end = strchr(format + 1, ')')))
|
||||||
|
die(_("bad ls-tree format: element '%s' "
|
||||||
|
"does not end in ')'"), format);
|
||||||
|
else if (skip_prefix(format, "(objectmode)", &format))
|
||||||
|
strbuf_addf(&sb, "%06o", mode);
|
||||||
|
else if (skip_prefix(format, "(objecttype)", &format))
|
||||||
|
strbuf_addstr(&sb, type_name(type));
|
||||||
|
else if (skip_prefix(format, "(objectsize:padded)", &format))
|
||||||
|
expand_objectsize(&sb, oid, type, 1);
|
||||||
|
else if (skip_prefix(format, "(objectsize)", &format))
|
||||||
|
expand_objectsize(&sb, oid, type, 0);
|
||||||
|
else if (skip_prefix(format, "(objectname)", &format))
|
||||||
|
strbuf_add_unique_abbrev(&sb, oid, options->abbrev);
|
||||||
|
else if (skip_prefix(format, "(path)", &format)) {
|
||||||
|
const char *name;
|
||||||
|
const char *prefix = options->chomp_prefix ?
|
||||||
|
options->ls_tree_prefix : NULL;
|
||||||
|
struct strbuf sbuf = STRBUF_INIT;
|
||||||
|
size_t baselen = base->len;
|
||||||
|
|
||||||
|
strbuf_addstr(base, pathname);
|
||||||
|
name = relative_path(base->buf, prefix, &sbuf);
|
||||||
|
quote_c_style(name, &sb, NULL, 0);
|
||||||
|
strbuf_setlen(base, baselen);
|
||||||
|
strbuf_release(&sbuf);
|
||||||
|
} else
|
||||||
|
die(_("bad ls-tree format: %%%.*s"),
|
||||||
|
(int)(end - format + 1), format);
|
||||||
|
}
|
||||||
strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
|
strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
|
||||||
fwrite(sb.buf, sb.len, 1, stdout);
|
fwrite(sb.buf, sb.len, 1, stdout);
|
||||||
strbuf_release(&sb);
|
strbuf_release(&sb);
|
||||||
|
|
22
convert.c
22
convert.c
|
@ -634,23 +634,21 @@ static int filter_buffer_or_fd(int in UNUSED, int out, void *data)
|
||||||
*/
|
*/
|
||||||
struct child_process child_process = CHILD_PROCESS_INIT;
|
struct child_process child_process = CHILD_PROCESS_INIT;
|
||||||
struct filter_params *params = (struct filter_params *)data;
|
struct filter_params *params = (struct filter_params *)data;
|
||||||
|
const char *format = params->cmd;
|
||||||
int write_err, status;
|
int write_err, status;
|
||||||
|
|
||||||
/* apply % substitution to cmd */
|
/* apply % substitution to cmd */
|
||||||
struct strbuf cmd = STRBUF_INIT;
|
struct strbuf cmd = STRBUF_INIT;
|
||||||
struct strbuf path = STRBUF_INIT;
|
|
||||||
struct strbuf_expand_dict_entry dict[] = {
|
|
||||||
{ "f", NULL, },
|
|
||||||
{ NULL, NULL, },
|
|
||||||
};
|
|
||||||
|
|
||||||
/* quote the path to preserve spaces, etc. */
|
/* expand all %f with the quoted path; quote to preserve space, etc. */
|
||||||
sq_quote_buf(&path, params->path);
|
while (strbuf_expand_step(&cmd, &format)) {
|
||||||
dict[0].value = path.buf;
|
if (skip_prefix(format, "%", &format))
|
||||||
|
strbuf_addch(&cmd, '%');
|
||||||
/* expand all %f with the quoted path */
|
else if (skip_prefix(format, "f", &format))
|
||||||
strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
|
sq_quote_buf(&cmd, params->path);
|
||||||
strbuf_release(&path);
|
else
|
||||||
|
strbuf_addch(&cmd, '%');
|
||||||
|
}
|
||||||
|
|
||||||
strvec_push(&child_process.args, cmd.buf);
|
strvec_push(&child_process.args, cmd.buf);
|
||||||
child_process.use_shell = 1;
|
child_process.use_shell = 1;
|
||||||
|
|
61
daemon.c
61
daemon.c
|
@ -144,42 +144,6 @@ static void NORETURN daemon_die(const char *err, va_list params)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct expand_path_context {
|
|
||||||
const char *directory;
|
|
||||||
struct hostinfo *hostinfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t expand_path(struct strbuf *sb, const char *placeholder, void *ctx)
|
|
||||||
{
|
|
||||||
struct expand_path_context *context = ctx;
|
|
||||||
struct hostinfo *hi = context->hostinfo;
|
|
||||||
|
|
||||||
switch (placeholder[0]) {
|
|
||||||
case 'H':
|
|
||||||
strbuf_addbuf(sb, &hi->hostname);
|
|
||||||
return 1;
|
|
||||||
case 'C':
|
|
||||||
if (placeholder[1] == 'H') {
|
|
||||||
strbuf_addstr(sb, get_canon_hostname(hi));
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
if (placeholder[1] == 'P') {
|
|
||||||
strbuf_addstr(sb, get_ip_address(hi));
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
strbuf_addbuf(sb, &hi->tcp_port);
|
|
||||||
return 1;
|
|
||||||
case 'D':
|
|
||||||
strbuf_addstr(sb, context->directory);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *path_ok(const char *directory, struct hostinfo *hi)
|
static const char *path_ok(const char *directory, struct hostinfo *hi)
|
||||||
{
|
{
|
||||||
static char rpath[PATH_MAX];
|
static char rpath[PATH_MAX];
|
||||||
|
@ -223,10 +187,7 @@ static const char *path_ok(const char *directory, struct hostinfo *hi)
|
||||||
}
|
}
|
||||||
else if (interpolated_path && hi->saw_extended_args) {
|
else if (interpolated_path && hi->saw_extended_args) {
|
||||||
struct strbuf expanded_path = STRBUF_INIT;
|
struct strbuf expanded_path = STRBUF_INIT;
|
||||||
struct expand_path_context context;
|
const char *format = interpolated_path;
|
||||||
|
|
||||||
context.directory = directory;
|
|
||||||
context.hostinfo = hi;
|
|
||||||
|
|
||||||
if (*dir != '/') {
|
if (*dir != '/') {
|
||||||
/* Allow only absolute */
|
/* Allow only absolute */
|
||||||
|
@ -234,8 +195,24 @@ static const char *path_ok(const char *directory, struct hostinfo *hi)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
strbuf_expand(&expanded_path, interpolated_path,
|
while (strbuf_expand_step(&expanded_path, &format)) {
|
||||||
expand_path, &context);
|
if (skip_prefix(format, "%", &format))
|
||||||
|
strbuf_addch(&expanded_path, '%');
|
||||||
|
else if (skip_prefix(format, "H", &format))
|
||||||
|
strbuf_addbuf(&expanded_path, &hi->hostname);
|
||||||
|
else if (skip_prefix(format, "CH", &format))
|
||||||
|
strbuf_addstr(&expanded_path,
|
||||||
|
get_canon_hostname(hi));
|
||||||
|
else if (skip_prefix(format, "IP", &format))
|
||||||
|
strbuf_addstr(&expanded_path,
|
||||||
|
get_ip_address(hi));
|
||||||
|
else if (skip_prefix(format, "P", &format))
|
||||||
|
strbuf_addbuf(&expanded_path, &hi->tcp_port);
|
||||||
|
else if (skip_prefix(format, "D", &format))
|
||||||
|
strbuf_addstr(&expanded_path, directory);
|
||||||
|
else
|
||||||
|
strbuf_addch(&expanded_path, '%');
|
||||||
|
}
|
||||||
|
|
||||||
rlen = strlcpy(interp_path, expanded_path.buf,
|
rlen = strlcpy(interp_path, expanded_path.buf,
|
||||||
sizeof(interp_path));
|
sizeof(interp_path));
|
||||||
|
|
33
merge-ll.c
33
merge-ll.c
|
@ -192,24 +192,15 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
|
||||||
const struct ll_merge_options *opts,
|
const struct ll_merge_options *opts,
|
||||||
int marker_size)
|
int marker_size)
|
||||||
{
|
{
|
||||||
char temp[4][50];
|
char temp[3][50];
|
||||||
struct strbuf cmd = STRBUF_INIT;
|
struct strbuf cmd = STRBUF_INIT;
|
||||||
struct strbuf_expand_dict_entry dict[6];
|
const char *format = fn->cmdline;
|
||||||
struct strbuf path_sq = STRBUF_INIT;
|
|
||||||
struct child_process child = CHILD_PROCESS_INIT;
|
struct child_process child = CHILD_PROCESS_INIT;
|
||||||
int status, fd, i;
|
int status, fd, i;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
enum ll_merge_result ret;
|
enum ll_merge_result ret;
|
||||||
assert(opts);
|
assert(opts);
|
||||||
|
|
||||||
sq_quote_buf(&path_sq, path);
|
|
||||||
dict[0].placeholder = "O"; dict[0].value = temp[0];
|
|
||||||
dict[1].placeholder = "A"; dict[1].value = temp[1];
|
|
||||||
dict[2].placeholder = "B"; dict[2].value = temp[2];
|
|
||||||
dict[3].placeholder = "L"; dict[3].value = temp[3];
|
|
||||||
dict[4].placeholder = "P"; dict[4].value = path_sq.buf;
|
|
||||||
dict[5].placeholder = NULL; dict[5].value = NULL;
|
|
||||||
|
|
||||||
if (!fn->cmdline)
|
if (!fn->cmdline)
|
||||||
die("custom merge driver %s lacks command line.", fn->name);
|
die("custom merge driver %s lacks command line.", fn->name);
|
||||||
|
|
||||||
|
@ -218,9 +209,23 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
|
||||||
create_temp(orig, temp[0], sizeof(temp[0]));
|
create_temp(orig, temp[0], sizeof(temp[0]));
|
||||||
create_temp(src1, temp[1], sizeof(temp[1]));
|
create_temp(src1, temp[1], sizeof(temp[1]));
|
||||||
create_temp(src2, temp[2], sizeof(temp[2]));
|
create_temp(src2, temp[2], sizeof(temp[2]));
|
||||||
xsnprintf(temp[3], sizeof(temp[3]), "%d", marker_size);
|
|
||||||
|
|
||||||
strbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict);
|
while (strbuf_expand_step(&cmd, &format)) {
|
||||||
|
if (skip_prefix(format, "%", &format))
|
||||||
|
strbuf_addch(&cmd, '%');
|
||||||
|
else if (skip_prefix(format, "O", &format))
|
||||||
|
strbuf_addstr(&cmd, temp[0]);
|
||||||
|
else if (skip_prefix(format, "A", &format))
|
||||||
|
strbuf_addstr(&cmd, temp[1]);
|
||||||
|
else if (skip_prefix(format, "B", &format))
|
||||||
|
strbuf_addstr(&cmd, temp[2]);
|
||||||
|
else if (skip_prefix(format, "L", &format))
|
||||||
|
strbuf_addf(&cmd, "%d", marker_size);
|
||||||
|
else if (skip_prefix(format, "P", &format))
|
||||||
|
sq_quote_buf(&cmd, path);
|
||||||
|
else
|
||||||
|
strbuf_addch(&cmd, '%');
|
||||||
|
}
|
||||||
|
|
||||||
child.use_shell = 1;
|
child.use_shell = 1;
|
||||||
strvec_push(&child.args, cmd.buf);
|
strvec_push(&child.args, cmd.buf);
|
||||||
|
@ -242,8 +247,6 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
unlink_or_warn(temp[i]);
|
unlink_or_warn(temp[i]);
|
||||||
strbuf_release(&cmd);
|
strbuf_release(&cmd);
|
||||||
strbuf_release(&path_sq);
|
|
||||||
|
|
||||||
if (!status)
|
if (!status)
|
||||||
ret = LL_MERGE_OK;
|
ret = LL_MERGE_OK;
|
||||||
else if (status <= 128)
|
else if (status <= 128)
|
||||||
|
|
99
pretty.c
99
pretty.c
|
@ -1251,6 +1251,27 @@ static int format_trailer_match_cb(const struct strbuf *key, void *ud)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct strbuf *expand_separator(struct strbuf *sb,
|
||||||
|
const char *argval, size_t arglen)
|
||||||
|
{
|
||||||
|
char *fmt = xstrndup(argval, arglen);
|
||||||
|
const char *format = fmt;
|
||||||
|
|
||||||
|
strbuf_reset(sb);
|
||||||
|
while (strbuf_expand_step(sb, &format)) {
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (skip_prefix(format, "%", &format))
|
||||||
|
strbuf_addch(sb, '%');
|
||||||
|
else if ((len = strbuf_expand_literal(sb, format)))
|
||||||
|
format += len;
|
||||||
|
else
|
||||||
|
strbuf_addch(sb, '%');
|
||||||
|
}
|
||||||
|
free(fmt);
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
int format_set_trailers_options(struct process_trailer_options *opts,
|
int format_set_trailers_options(struct process_trailer_options *opts,
|
||||||
struct string_list *filter_list,
|
struct string_list *filter_list,
|
||||||
struct strbuf *sepbuf,
|
struct strbuf *sepbuf,
|
||||||
|
@ -1279,21 +1300,9 @@ int format_set_trailers_options(struct process_trailer_options *opts,
|
||||||
opts->filter_data = filter_list;
|
opts->filter_data = filter_list;
|
||||||
opts->only_trailers = 1;
|
opts->only_trailers = 1;
|
||||||
} else if (match_placeholder_arg_value(*arg, "separator", arg, &argval, &arglen)) {
|
} else if (match_placeholder_arg_value(*arg, "separator", arg, &argval, &arglen)) {
|
||||||
char *fmt;
|
opts->separator = expand_separator(sepbuf, argval, arglen);
|
||||||
|
|
||||||
strbuf_reset(sepbuf);
|
|
||||||
fmt = xstrndup(argval, arglen);
|
|
||||||
strbuf_expand(sepbuf, fmt, strbuf_expand_literal_cb, NULL);
|
|
||||||
free(fmt);
|
|
||||||
opts->separator = sepbuf;
|
|
||||||
} else if (match_placeholder_arg_value(*arg, "key_value_separator", arg, &argval, &arglen)) {
|
} else if (match_placeholder_arg_value(*arg, "key_value_separator", arg, &argval, &arglen)) {
|
||||||
char *fmt;
|
opts->key_value_separator = expand_separator(kvsepbuf, argval, arglen);
|
||||||
|
|
||||||
strbuf_reset(kvsepbuf);
|
|
||||||
fmt = xstrndup(argval, arglen);
|
|
||||||
strbuf_expand(kvsepbuf, fmt, strbuf_expand_literal_cb, NULL);
|
|
||||||
free(fmt);
|
|
||||||
opts->key_value_separator = kvsepbuf;
|
|
||||||
} else if (!match_placeholder_bool_arg(*arg, "only", arg, &opts->only_trailers) &&
|
} else if (!match_placeholder_bool_arg(*arg, "only", arg, &opts->only_trailers) &&
|
||||||
!match_placeholder_bool_arg(*arg, "unfold", arg, &opts->unfold) &&
|
!match_placeholder_bool_arg(*arg, "unfold", arg, &opts->unfold) &&
|
||||||
!match_placeholder_bool_arg(*arg, "keyonly", arg, &opts->key_only) &&
|
!match_placeholder_bool_arg(*arg, "keyonly", arg, &opts->key_only) &&
|
||||||
|
@ -1387,7 +1396,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
|
||||||
char **slot;
|
char **slot;
|
||||||
|
|
||||||
/* these are independent of the commit */
|
/* these are independent of the commit */
|
||||||
res = strbuf_expand_literal_cb(sb, placeholder, NULL);
|
res = strbuf_expand_literal(sb, placeholder);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
@ -1805,7 +1814,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
|
||||||
|
|
||||||
static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
|
static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
|
||||||
const char *placeholder,
|
const char *placeholder,
|
||||||
void *context)
|
struct format_commit_context *context)
|
||||||
{
|
{
|
||||||
size_t consumed, orig_len;
|
size_t consumed, orig_len;
|
||||||
enum {
|
enum {
|
||||||
|
@ -1844,7 +1853,7 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
|
||||||
}
|
}
|
||||||
|
|
||||||
orig_len = sb->len;
|
orig_len = sb->len;
|
||||||
if (((struct format_commit_context *)context)->flush_type != no_flush)
|
if ((context)->flush_type != no_flush)
|
||||||
consumed = format_and_pad_commit(sb, placeholder, context);
|
consumed = format_and_pad_commit(sb, placeholder, context);
|
||||||
else
|
else
|
||||||
consumed = format_commit_one(sb, placeholder, context);
|
consumed = format_commit_one(sb, placeholder, context);
|
||||||
|
@ -1863,30 +1872,6 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
|
||||||
return consumed + 1;
|
return consumed + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t userformat_want_item(struct strbuf *sb UNUSED,
|
|
||||||
const char *placeholder,
|
|
||||||
void *context)
|
|
||||||
{
|
|
||||||
struct userformat_want *w = context;
|
|
||||||
|
|
||||||
if (*placeholder == '+' || *placeholder == '-' || *placeholder == ' ')
|
|
||||||
placeholder++;
|
|
||||||
|
|
||||||
switch (*placeholder) {
|
|
||||||
case 'N':
|
|
||||||
w->notes = 1;
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
w->source = 1;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
case 'D':
|
|
||||||
w->decorate = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void userformat_find_requirements(const char *fmt, struct userformat_want *w)
|
void userformat_find_requirements(const char *fmt, struct userformat_want *w)
|
||||||
{
|
{
|
||||||
struct strbuf dummy = STRBUF_INIT;
|
struct strbuf dummy = STRBUF_INIT;
|
||||||
|
@ -1896,7 +1881,26 @@ void userformat_find_requirements(const char *fmt, struct userformat_want *w)
|
||||||
return;
|
return;
|
||||||
fmt = user_format;
|
fmt = user_format;
|
||||||
}
|
}
|
||||||
strbuf_expand(&dummy, fmt, userformat_want_item, w);
|
while (strbuf_expand_step(&dummy, &fmt)) {
|
||||||
|
if (skip_prefix(fmt, "%", &fmt))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (*fmt == '+' || *fmt == '-' || *fmt == ' ')
|
||||||
|
fmt++;
|
||||||
|
|
||||||
|
switch (*fmt) {
|
||||||
|
case 'N':
|
||||||
|
w->notes = 1;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
w->source = 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
w->decorate = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
strbuf_release(&dummy);
|
strbuf_release(&dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1914,7 +1918,16 @@ void repo_format_commit_message(struct repository *r,
|
||||||
const char *output_enc = pretty_ctx->output_encoding;
|
const char *output_enc = pretty_ctx->output_encoding;
|
||||||
const char *utf8 = "UTF-8";
|
const char *utf8 = "UTF-8";
|
||||||
|
|
||||||
strbuf_expand(sb, format, format_commit_item, &context);
|
while (strbuf_expand_step(sb, &format)) {
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (skip_prefix(format, "%", &format))
|
||||||
|
strbuf_addch(sb, '%');
|
||||||
|
else if ((len = format_commit_item(sb, format, &context)))
|
||||||
|
format += len;
|
||||||
|
else
|
||||||
|
strbuf_addch(sb, '%');
|
||||||
|
}
|
||||||
rewrap_message_tail(sb, &context, 0, 0, 0);
|
rewrap_message_tail(sb, &context, 0, 0, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
58
strbuf.c
58
strbuf.c
|
@ -416,36 +416,19 @@ void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
|
||||||
strbuf_setlen(sb, sb->len + len);
|
strbuf_setlen(sb, sb->len + len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
|
int strbuf_expand_step(struct strbuf *sb, const char **formatp)
|
||||||
void *context)
|
|
||||||
{
|
{
|
||||||
for (;;) {
|
const char *format = *formatp;
|
||||||
const char *percent;
|
const char *percent = strchrnul(format, '%');
|
||||||
size_t consumed;
|
|
||||||
|
|
||||||
percent = strchrnul(format, '%');
|
strbuf_add(sb, format, percent - format);
|
||||||
strbuf_add(sb, format, percent - format);
|
if (!*percent)
|
||||||
if (!*percent)
|
return 0;
|
||||||
break;
|
*formatp = percent + 1;
|
||||||
format = percent + 1;
|
return 1;
|
||||||
|
|
||||||
if (*format == '%') {
|
|
||||||
strbuf_addch(sb, '%');
|
|
||||||
format++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
consumed = fn(sb, format, context);
|
|
||||||
if (consumed)
|
|
||||||
format += consumed;
|
|
||||||
else
|
|
||||||
strbuf_addch(sb, '%');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t strbuf_expand_literal_cb(struct strbuf *sb,
|
size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder)
|
||||||
const char *placeholder,
|
|
||||||
void *context UNUSED)
|
|
||||||
{
|
{
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
|
@ -464,22 +447,6 @@ size_t strbuf_expand_literal_cb(struct strbuf *sb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
|
|
||||||
void *context)
|
|
||||||
{
|
|
||||||
struct strbuf_expand_dict_entry *e = context;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
|
|
||||||
if (!strncmp(placeholder, e->placeholder, len)) {
|
|
||||||
if (e->value)
|
|
||||||
strbuf_addstr(sb, e->value);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
|
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
|
||||||
{
|
{
|
||||||
size_t i, len = src->len;
|
size_t i, len = src->len;
|
||||||
|
@ -1028,12 +995,7 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
|
||||||
* we want for %z, but the computation for %s has to convert to number
|
* we want for %z, but the computation for %s has to convert to number
|
||||||
* of seconds.
|
* of seconds.
|
||||||
*/
|
*/
|
||||||
for (;;) {
|
while (strbuf_expand_step(&munged_fmt, &fmt)) {
|
||||||
const char *percent = strchrnul(fmt, '%');
|
|
||||||
strbuf_add(&munged_fmt, fmt, percent - fmt);
|
|
||||||
if (!*percent)
|
|
||||||
break;
|
|
||||||
fmt = percent + 1;
|
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
case '%':
|
case '%':
|
||||||
strbuf_addstr(&munged_fmt, "%%");
|
strbuf_addstr(&munged_fmt, "%%");
|
||||||
|
|
57
strbuf.h
57
strbuf.h
|
@ -314,58 +314,19 @@ const char *strbuf_join_argv(struct strbuf *buf, int argc,
|
||||||
const char **argv, char delim);
|
const char **argv, char delim);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function can be used to expand a format string containing
|
* Used with `strbuf_expand_step` to expand the literals %n and %x
|
||||||
* placeholders. To that end, it parses the string and calls the specified
|
* followed by two hexadecimal digits. Returns the number of recognized
|
||||||
* function for every percent sign found.
|
* characters.
|
||||||
*
|
|
||||||
* The callback function is given a pointer to the character after the `%`
|
|
||||||
* and a pointer to the struct strbuf. It is expected to add the expanded
|
|
||||||
* version of the placeholder to the strbuf, e.g. to add a newline
|
|
||||||
* character if the letter `n` appears after a `%`. The function returns
|
|
||||||
* the length of the placeholder recognized and `strbuf_expand()` skips
|
|
||||||
* over it.
|
|
||||||
*
|
|
||||||
* The format `%%` is automatically expanded to a single `%` as a quoting
|
|
||||||
* mechanism; callers do not need to handle the `%` placeholder themselves,
|
|
||||||
* and the callback function will not be invoked for this placeholder.
|
|
||||||
*
|
|
||||||
* All other characters (non-percent and not skipped ones) are copied
|
|
||||||
* verbatim to the strbuf. If the callback returned zero, meaning that the
|
|
||||||
* placeholder is unknown, then the percent sign is copied, too.
|
|
||||||
*
|
|
||||||
* In order to facilitate caching and to make it possible to give
|
|
||||||
* parameters to the callback, `strbuf_expand()` passes a context
|
|
||||||
* pointer with any kind of data.
|
|
||||||
*/
|
*/
|
||||||
typedef size_t (*expand_fn_t) (struct strbuf *sb,
|
size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder);
|
||||||
const char *placeholder,
|
|
||||||
void *context);
|
|
||||||
void strbuf_expand(struct strbuf *sb,
|
|
||||||
const char *format,
|
|
||||||
expand_fn_t fn,
|
|
||||||
void *context);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used as callback for `strbuf_expand` to only expand literals
|
* If the string pointed to by `formatp` contains a percent sign ("%"),
|
||||||
* (i.e. %n and %xNN). The context argument is ignored.
|
* advance it to point to the character following the next one and
|
||||||
|
* return 1, otherwise return 0. Append the substring before that
|
||||||
|
* percent sign to `sb`, or the whole string if there is none.
|
||||||
*/
|
*/
|
||||||
size_t strbuf_expand_literal_cb(struct strbuf *sb,
|
int strbuf_expand_step(struct strbuf *sb, const char **formatp);
|
||||||
const char *placeholder,
|
|
||||||
void *context);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used as callback for `strbuf_expand()`, expects an array of
|
|
||||||
* struct strbuf_expand_dict_entry as context, i.e. pairs of
|
|
||||||
* placeholder and replacement string. The array needs to be
|
|
||||||
* terminated by an entry with placeholder set to NULL.
|
|
||||||
*/
|
|
||||||
struct strbuf_expand_dict_entry {
|
|
||||||
const char *placeholder;
|
|
||||||
const char *value;
|
|
||||||
};
|
|
||||||
size_t strbuf_expand_dict_cb(struct strbuf *sb,
|
|
||||||
const char *placeholder,
|
|
||||||
void *context);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append the contents of one strbuf to another, quoting any
|
* Append the contents of one strbuf to another, quoting any
|
||||||
|
|
Загрузка…
Ссылка в новой задаче