2023-04-11 15:42:03 +08:00
|
|
|
#include "git-compat-util.h"
|
|
|
|
#include "path.h"
|
2005-07-08 14:58:32 +08:00
|
|
|
#include "quote.h"
|
2023-02-24 08:09:34 +08:00
|
|
|
#include "strbuf.h"
|
2020-07-29 04:23:39 +08:00
|
|
|
#include "strvec.h"
|
2005-07-08 14:58:32 +08:00
|
|
|
|
2008-06-28 04:46:42 +08:00
|
|
|
int quote_path_fully = 1;
|
|
|
|
|
2015-10-08 06:05:50 +08:00
|
|
|
static inline int need_bs_quote(char c)
|
|
|
|
{
|
|
|
|
return (c == '\'' || c == '!');
|
|
|
|
}
|
|
|
|
|
2005-07-08 14:58:32 +08:00
|
|
|
/* Help to copy the thing properly quoted for the shell safety.
|
2005-10-11 05:46:10 +08:00
|
|
|
* any single quote is replaced with '\'', any exclamation point
|
|
|
|
* is replaced with '\!', and the whole thing is enclosed in a
|
2015-10-08 06:05:49 +08:00
|
|
|
* single quote pair.
|
2005-07-08 14:58:32 +08:00
|
|
|
*
|
|
|
|
* E.g.
|
|
|
|
* original sq_quote result
|
|
|
|
* name ==> name ==> 'name'
|
|
|
|
* a b ==> a b ==> 'a b'
|
|
|
|
* a'b ==> a'\''b ==> 'a'\''b'
|
2005-10-11 05:46:10 +08:00
|
|
|
* a!b ==> a'\!'b ==> 'a'\!'b'
|
2005-07-08 14:58:32 +08:00
|
|
|
*/
|
2007-09-20 06:42:13 +08:00
|
|
|
void sq_quote_buf(struct strbuf *dst, const char *src)
|
2005-10-11 05:46:10 +08:00
|
|
|
{
|
2007-09-20 06:42:13 +08:00
|
|
|
char *to_free = NULL;
|
|
|
|
|
|
|
|
if (dst->buf == src)
|
2007-09-27 18:58:23 +08:00
|
|
|
to_free = strbuf_detach(dst, NULL);
|
2007-09-20 06:42:13 +08:00
|
|
|
|
|
|
|
strbuf_addch(dst, '\'');
|
|
|
|
while (*src) {
|
2007-11-05 04:26:22 +08:00
|
|
|
size_t len = strcspn(src, "'!");
|
2007-09-20 06:42:13 +08:00
|
|
|
strbuf_add(dst, src, len);
|
|
|
|
src += len;
|
|
|
|
while (need_bs_quote(*src)) {
|
|
|
|
strbuf_addstr(dst, "'\\");
|
|
|
|
strbuf_addch(dst, *src++);
|
|
|
|
strbuf_addch(dst, '\'');
|
2005-07-08 14:58:32 +08:00
|
|
|
}
|
|
|
|
}
|
2007-09-20 06:42:13 +08:00
|
|
|
strbuf_addch(dst, '\'');
|
|
|
|
free(to_free);
|
2005-10-11 05:46:10 +08:00
|
|
|
}
|
|
|
|
|
2018-01-15 18:59:44 +08:00
|
|
|
void sq_quote_buf_pretty(struct strbuf *dst, const char *src)
|
|
|
|
{
|
|
|
|
static const char ok_punct[] = "+,-./:=@_^";
|
|
|
|
const char *p;
|
|
|
|
|
2019-10-08 03:38:56 +08:00
|
|
|
/* Avoid losing a zero-length string by adding '' */
|
|
|
|
if (!*src) {
|
|
|
|
strbuf_addstr(dst, "''");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-15 18:59:44 +08:00
|
|
|
for (p = src; *p; p++) {
|
2020-02-23 02:51:13 +08:00
|
|
|
if (!isalnum(*p) && !strchr(ok_punct, *p)) {
|
2018-01-15 18:59:44 +08:00
|
|
|
sq_quote_buf(dst, src);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we get here, we did not need quoting */
|
|
|
|
strbuf_addstr(dst, src);
|
|
|
|
}
|
|
|
|
|
2016-03-01 06:58:34 +08:00
|
|
|
void sq_quotef(struct strbuf *dst, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
struct strbuf src = STRBUF_INIT;
|
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
strbuf_vaddf(&src, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
sq_quote_buf(dst, src.buf);
|
|
|
|
strbuf_release(&src);
|
|
|
|
}
|
|
|
|
|
2018-01-15 18:59:43 +08:00
|
|
|
void sq_quote_argv(struct strbuf *dst, const char **argv)
|
2006-08-31 14:42:11 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Copy into destination buffer. */
|
2007-12-03 12:51:50 +08:00
|
|
|
strbuf_grow(dst, 255);
|
|
|
|
for (i = 0; argv[i]; ++i) {
|
2007-09-20 06:42:13 +08:00
|
|
|
strbuf_addch(dst, ' ');
|
|
|
|
sq_quote_buf(dst, argv[i]);
|
2006-08-31 14:42:11 +08:00
|
|
|
}
|
2006-09-11 12:59:22 +08:00
|
|
|
}
|
|
|
|
|
2019-08-09 23:00:55 +08:00
|
|
|
/*
|
|
|
|
* Legacy function to append each argv value, quoted as necessasry,
|
|
|
|
* with whitespace before each value. This results in a leading
|
|
|
|
* space in the result.
|
|
|
|
*/
|
2018-01-15 18:59:44 +08:00
|
|
|
void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
|
2019-08-09 23:00:55 +08:00
|
|
|
{
|
|
|
|
if (argv[0])
|
|
|
|
strbuf_addch(dst, ' ');
|
|
|
|
sq_append_quote_argv_pretty(dst, argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Append each argv value, quoted as necessary, with whitespace between them.
|
|
|
|
*/
|
|
|
|
void sq_append_quote_argv_pretty(struct strbuf *dst, const char **argv)
|
2018-01-15 18:59:44 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; argv[i]; i++) {
|
2019-08-09 23:00:55 +08:00
|
|
|
if (i > 0)
|
|
|
|
strbuf_addch(dst, ' ');
|
2018-01-15 18:59:44 +08:00
|
|
|
sq_quote_buf_pretty(dst, argv[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-12 20:26:49 +08:00
|
|
|
char *sq_dequote_step(char *arg, char **next)
|
2005-10-24 05:30:45 +08:00
|
|
|
{
|
|
|
|
char *dst = arg;
|
|
|
|
char *src = arg;
|
|
|
|
char c;
|
|
|
|
|
|
|
|
if (*src != '\'')
|
|
|
|
return NULL;
|
|
|
|
for (;;) {
|
|
|
|
c = *++src;
|
|
|
|
if (!c)
|
|
|
|
return NULL;
|
|
|
|
if (c != '\'') {
|
|
|
|
*dst++ = c;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* We stepped out of sq */
|
|
|
|
switch (*++src) {
|
|
|
|
case '\0':
|
|
|
|
*dst = 0;
|
2009-03-29 17:44:44 +08:00
|
|
|
if (next)
|
|
|
|
*next = NULL;
|
2005-10-24 05:30:45 +08:00
|
|
|
return arg;
|
|
|
|
case '\\':
|
sq_dequote: fix extra consumption of source string
This fixes a (probably harmless) parsing problem in
sq_dequote_step(), in which we parse some bogus input
incorrectly rather than complaining that it's bogus.
Our shell-dequoting function is very strict: it can unquote
everything generated by sq_quote(), but not arbitrary
strings. In particular, it only allows characters outside of
the single-quoted string if they are immediately backslashed
and then the single-quoted string is resumed. So:
'foo'\''bar'
is OK. But these are not:
'foo'\'bar
'foo'\'
'foo'\'\''bar'
even though they are all valid shell. The parser has a funny
corner case here. When we see a backslashed character, we
keep incrementing the "src" pointer as we parse it. For a
single sq_dequote() call, that's OK; our next step is to
bail with an error, and we don't care where "src" points.
But if we're parsing multiple strings with sq_dequote_to_argv(),
then our next step is to see if the string is followed by
whitespace. Because we erroneously incremented the "src"
pointer, we don't barf on the bogus backslash that we
skipped. Instead, we may find whitespace that immediately
follows it, and continue as if all is well (skipping the
backslashed character completely!).
In practice, this shouldn't be a big deal. The input is
bogus, and our sq_quote() would never generate this bogus
input. In all but one callers, we are parsing input created
by an earlier call to sq_quote(). That final case is "git
shell", which parses shell-quoting generated by the client.
And in that case we use the singular sq_quote(), which has
always behaved correctly.
One might also wonder if you could provoke a read past the
end of the string. But the answer is no; we still parse
character by character, and would never advance past a NUL.
This patch implements the minimal fix, along with
documenting the restriction (which confused at least me
while reading the code). We should possibly consider
being more liberal in accepting valid shell-quoted words. I
suspect the code may actually be simpler, and it would be
more friendly to anybody generating or editing input by
hand. But I wanted to fix just the immediate bug in this
patch.
We don't have a direct way to unit-test the sq_dequote()
functions, but we can do this by feeding input to
GIT_CONFIG_PARAMETERS (which is not normally a user-facing
interface, but serves here as it expects to see sq_quote()
input from "git -c"). I've included both a bogus example,
and a related "good" one to confirm that we still parse it
correctly.
Noticed-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-14 07:41:49 +08:00
|
|
|
/*
|
|
|
|
* Allow backslashed characters outside of
|
|
|
|
* single-quotes only if they need escaping,
|
|
|
|
* and only if we resume the single-quoted part
|
|
|
|
* afterward.
|
|
|
|
*/
|
|
|
|
if (need_bs_quote(src[1]) && src[2] == '\'') {
|
|
|
|
*dst++ = src[1];
|
|
|
|
src += 2;
|
2005-10-24 05:30:45 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Fallthrough */
|
|
|
|
default:
|
2021-01-12 20:26:49 +08:00
|
|
|
if (!next)
|
2009-03-29 17:44:44 +08:00
|
|
|
return NULL;
|
|
|
|
*dst = 0;
|
|
|
|
*next = src;
|
|
|
|
return arg;
|
2005-10-24 05:30:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-29 17:44:44 +08:00
|
|
|
char *sq_dequote(char *arg)
|
|
|
|
{
|
|
|
|
return sq_dequote_step(arg, NULL);
|
|
|
|
}
|
|
|
|
|
2011-09-14 05:58:08 +08:00
|
|
|
static int sq_dequote_to_argv_internal(char *arg,
|
|
|
|
const char ***argv, int *nr, int *alloc,
|
2020-07-29 04:25:12 +08:00
|
|
|
struct strvec *array)
|
2009-03-29 17:44:52 +08:00
|
|
|
{
|
|
|
|
char *next = arg;
|
|
|
|
|
|
|
|
if (!*arg)
|
|
|
|
return 0;
|
|
|
|
do {
|
|
|
|
char *dequoted = sq_dequote_step(next, &next);
|
|
|
|
if (!dequoted)
|
|
|
|
return -1;
|
2021-01-12 20:26:49 +08:00
|
|
|
if (next) {
|
|
|
|
char c;
|
|
|
|
if (!isspace(*next))
|
|
|
|
return -1;
|
|
|
|
do {
|
|
|
|
c = *++next;
|
|
|
|
} while (isspace(c));
|
|
|
|
}
|
2011-09-14 05:58:08 +08:00
|
|
|
if (argv) {
|
|
|
|
ALLOC_GROW(*argv, *nr + 1, *alloc);
|
|
|
|
(*argv)[(*nr)++] = dequoted;
|
|
|
|
}
|
|
|
|
if (array)
|
2020-07-29 04:25:12 +08:00
|
|
|
strvec_push(array, dequoted);
|
2009-03-29 17:44:52 +08:00
|
|
|
} while (next);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-14 05:58:08 +08:00
|
|
|
int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc)
|
|
|
|
{
|
|
|
|
return sq_dequote_to_argv_internal(arg, argv, nr, alloc, NULL);
|
|
|
|
}
|
|
|
|
|
2020-07-29 04:24:02 +08:00
|
|
|
int sq_dequote_to_strvec(char *arg, struct strvec *array)
|
2011-09-14 05:58:08 +08:00
|
|
|
{
|
|
|
|
return sq_dequote_to_argv_internal(arg, NULL, NULL, NULL, array);
|
|
|
|
}
|
|
|
|
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
/* 1 means: quote as octal
|
|
|
|
* 0 means: quote as octal if (quote_path_fully)
|
|
|
|
* -1 means: never quote
|
|
|
|
* c: quote as "\\c"
|
|
|
|
*/
|
|
|
|
#define X8(x) x, x, x, x, x, x, x, x
|
|
|
|
#define X16(x) X8(x), X8(x)
|
2020-09-11 01:01:58 +08:00
|
|
|
static signed char const cq_lookup[256] = {
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
/* 0 1 2 3 4 5 6 7 */
|
|
|
|
/* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a',
|
|
|
|
/* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1,
|
|
|
|
/* 0x10 */ X16(1),
|
|
|
|
/* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1,
|
|
|
|
/* 0x28 */ X16(-1), X16(-1), X16(-1),
|
|
|
|
/* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1,
|
|
|
|
/* 0x60 */ X16(-1), X8(-1),
|
|
|
|
/* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1,
|
|
|
|
/* 0x80 */ /* set to 0 */
|
|
|
|
};
|
|
|
|
|
2020-09-11 01:01:58 +08:00
|
|
|
static inline int cq_must_quote(char c)
|
2007-11-09 07:35:32 +08:00
|
|
|
{
|
2020-09-11 01:01:58 +08:00
|
|
|
return cq_lookup[(unsigned char)c] + quote_path_fully > 0;
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns the longest prefix not needing a quote up to maxlen if positive.
|
|
|
|
This stops at the first \0 because it's marked as a character needing an
|
|
|
|
escape */
|
|
|
|
static size_t next_quote_pos(const char *s, ssize_t maxlen)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
if (maxlen < 0) {
|
2020-09-11 01:01:58 +08:00
|
|
|
for (len = 0; !cq_must_quote(s[len]); len++);
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
} else {
|
2020-09-11 01:01:58 +08:00
|
|
|
for (len = 0; len < maxlen && !cq_must_quote(s[len]); len++);
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
}
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2005-10-15 12:54:47 +08:00
|
|
|
/*
|
|
|
|
* C-style name quoting.
|
|
|
|
*
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
* (1) if sb and fp are both NULL, inspect the input name and counts the
|
|
|
|
* number of bytes that are needed to hold c_style quoted version of name,
|
|
|
|
* counting the double quotes around it but not terminating NUL, and
|
|
|
|
* returns it.
|
|
|
|
* However, if name does not need c_style quoting, it returns 0.
|
2005-10-15 12:54:47 +08:00
|
|
|
*
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
* (2) if sb or fp are not NULL, it emits the c_style quoted version
|
|
|
|
* of name, enclosed with double quotes if asked and needed only.
|
|
|
|
* Return value is the same as in (1).
|
2005-10-15 12:54:47 +08:00
|
|
|
*/
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
|
2020-09-11 01:01:59 +08:00
|
|
|
struct strbuf *sb, FILE *fp, unsigned flags)
|
2005-10-15 12:54:47 +08:00
|
|
|
{
|
|
|
|
#undef EMIT
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
#define EMIT(c) \
|
|
|
|
do { \
|
|
|
|
if (sb) strbuf_addch(sb, (c)); \
|
|
|
|
if (fp) fputc((c), fp); \
|
|
|
|
count++; \
|
|
|
|
} while (0)
|
|
|
|
#define EMITBUF(s, l) \
|
|
|
|
do { \
|
|
|
|
if (sb) strbuf_add(sb, (s), (l)); \
|
|
|
|
if (fp) fwrite((s), (l), 1, fp); \
|
|
|
|
count += (l); \
|
|
|
|
} while (0)
|
|
|
|
|
2020-09-11 01:01:59 +08:00
|
|
|
int no_dq = !!(flags & CQUOTE_NODQ);
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
size_t len, count = 0;
|
|
|
|
const char *p = name;
|
2005-10-15 12:54:47 +08:00
|
|
|
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
for (;;) {
|
|
|
|
int ch;
|
2005-10-15 12:54:47 +08:00
|
|
|
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
len = next_quote_pos(p, maxlen);
|
2010-02-01 21:39:03 +08:00
|
|
|
if (len == maxlen || (maxlen < 0 && !p[len]))
|
2005-12-22 04:35:48 +08:00
|
|
|
break;
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
|
|
|
|
if (!no_dq && p == name)
|
|
|
|
EMIT('"');
|
|
|
|
|
|
|
|
EMITBUF(p, len);
|
|
|
|
EMIT('\\');
|
|
|
|
p += len;
|
|
|
|
ch = (unsigned char)*p++;
|
2010-02-01 21:39:03 +08:00
|
|
|
if (maxlen >= 0)
|
|
|
|
maxlen -= len + 1;
|
2020-09-11 01:01:58 +08:00
|
|
|
if (cq_lookup[ch] >= ' ') {
|
|
|
|
EMIT(cq_lookup[ch]);
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
} else {
|
|
|
|
EMIT(((ch >> 6) & 03) + '0');
|
|
|
|
EMIT(((ch >> 3) & 07) + '0');
|
|
|
|
EMIT(((ch >> 0) & 07) + '0');
|
2005-10-15 12:54:47 +08:00
|
|
|
}
|
|
|
|
}
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
|
|
|
|
EMITBUF(p, len);
|
|
|
|
if (p == name) /* no ending quote needed */
|
|
|
|
return 0;
|
|
|
|
|
2005-10-15 12:54:47 +08:00
|
|
|
if (!no_dq)
|
|
|
|
EMIT('"');
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
return count;
|
|
|
|
}
|
2005-10-15 12:54:47 +08:00
|
|
|
|
2020-09-11 01:01:59 +08:00
|
|
|
size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, unsigned flags)
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
{
|
2020-09-11 01:01:59 +08:00
|
|
|
return quote_c_style_counted(name, -1, sb, fp, flags);
|
2005-10-15 12:54:47 +08:00
|
|
|
}
|
|
|
|
|
2020-09-11 01:01:59 +08:00
|
|
|
void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path,
|
|
|
|
unsigned flags)
|
2007-12-27 09:13:36 +08:00
|
|
|
{
|
2020-09-11 01:01:59 +08:00
|
|
|
int nodq = !!(flags & CQUOTE_NODQ);
|
2007-12-27 09:13:36 +08:00
|
|
|
if (quote_c_style(prefix, NULL, NULL, 0) ||
|
|
|
|
quote_c_style(path, NULL, NULL, 0)) {
|
|
|
|
if (!nodq)
|
|
|
|
strbuf_addch(sb, '"');
|
2020-09-11 01:01:59 +08:00
|
|
|
quote_c_style(prefix, sb, NULL, CQUOTE_NODQ);
|
|
|
|
quote_c_style(path, sb, NULL, CQUOTE_NODQ);
|
2007-12-27 09:13:36 +08:00
|
|
|
if (!nodq)
|
|
|
|
strbuf_addch(sb, '"');
|
|
|
|
} else {
|
|
|
|
strbuf_addstr(sb, prefix);
|
|
|
|
strbuf_addstr(sb, path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
void write_name_quoted(const char *name, FILE *fp, int terminator)
|
2005-11-29 14:55:25 +08:00
|
|
|
{
|
Full rework of quote_c_style and write_name_quoted.
* quote_c_style works on a strbuf instead of a wild buffer.
* quote_c_style is now clever enough to not add double quotes if not needed.
* write_name_quoted inherits those advantages, but also take a different
set of arguments. Now instead of asking for quotes or not, you pass a
"terminator". If it's \0 then we assume you don't want to escape, else C
escaping is performed. In any case, the terminator is also appended to the
stream. It also no longer takes the prefix/prefix_len arguments, as it's
seldomly used, and makes some optimizations harder.
* write_name_quotedpfx is created to work like write_name_quoted and take
the prefix/prefix_len arguments.
Thanks to those API changes, diff.c has somehow lost weight, thanks to the
removal of functions that were wrappers around the old write_name_quoted
trying to give it a semantics like the new one, but performing a lot of
allocations for this goal. Now we always write directly to the stream, no
intermediate allocation is performed.
As a side effect of the refactor in builtin-apply.c, the length of the bar
graphs in diffstats are not affected anymore by the fact that the path was
clipped.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
2007-09-20 06:42:15 +08:00
|
|
|
if (terminator) {
|
|
|
|
quote_c_style(name, NULL, fp, 0);
|
|
|
|
} else {
|
|
|
|
fputs(name, fp);
|
|
|
|
}
|
|
|
|
fputc(terminator, fp);
|
|
|
|
}
|
|
|
|
|
2013-06-25 23:53:46 +08:00
|
|
|
void write_name_quoted_relative(const char *name, const char *prefix,
|
2010-06-03 21:36:31 +08:00
|
|
|
FILE *fp, int terminator)
|
2008-03-07 10:30:58 +08:00
|
|
|
{
|
2010-06-03 21:36:31 +08:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
quote.c: substitute path_relative with relative_path
Substitute the function path_relative in quote.c with the function
relative_path. Function relative_path can be treated as an enhanced
and more robust version of path_relative.
Outputs of path_relative and it's replacement (relative_path) are the
same for the following cases:
path prefix output of path_relative output of relative_path
======== ========= ======================= =======================
/a/b/c/ /a/b/ c/ c/
/a/b/c /a/b/ c c
/a/ /a/b/ ../ ../
/ /a/b/ ../../ ../../
/a/c /a/b/ ../c ../c
/x/y /a/b/ ../../x/y ../../x/y
a/b/c/ a/b/ c/ c/
a/ a/b/ ../ ../
x/y a/b/ ../../x/y ../../x/y
/a/b (empty) /a/b /a/b
/a/b (null) /a/b /a/b
a/b (empty) a/b a/b
a/b (null) a/b a/b
But if both of the path and the prefix are the same, or the returned
relative path should be the current directory, the outputs of both
functions are different. Function relative_path returns "./", while
function path_relative returns empty string.
path prefix output of path_relative output of relative_path
======== ========= ======================= =======================
/a/b/ /a/b/ (empty) ./
a/b/ a/b/ (empty) ./
(empty) (null) (empty) ./
(empty) (empty) (empty) ./
But the callers of path_relative can handle such cases, or never
encounter this issue at all, because:
* In function quote_path_relative, if the output of path_relative is
empty, append "./" to it, like:
if (!out->len)
strbuf_addstr(out, "./");
* Another caller is write_name_quoted_relative, which is only used
by builtin/ls-files.c. git-ls-files only show files, so path of
files will never be identical with the prefix of a directory.
The following differences show that path_relative does not handle
extra slashes properly:
path prefix output of path_relative output of relative_path
======== ========= ======================= =======================
/a//b//c/ //a/b// ../../../../a//b//c/ c/
a/b//c a//b ../b//c c
And if prefix has no trailing slash, path_relative does not work
properly either. But since prefix always has a trailing slash, it's
not a problem.
path prefix output of path_relative output of relative_path
======== ========= ======================= =======================
/a/b/c/ /a/b b/c/ c/
/a/b /a/b b ./
/a/b/ /a/b b/ ./
/a /a/b/ ../../a ../
a/b/c/ a/b b/c/ c/
a/b/ a/b b/ ./
a a/b ../a ../
x/y a/b/ ../x/y ../../x/y
a/c a/b c ../c
/a/ /a/b (empty) ../
(empty) /a/b ../../ ./
One tricky part in this conversion is write_name() function in
ls-files.c. It takes a counted string, <name, len>, that is to be
made relative to <prefix, prefix_len> and then quoted. Because
write_name_quoted_relative() still takes these two parameters as
counted string, but ignores the count and treat these two as
NUL-terminated strings, this conversion needs to be audited for its
callers:
- For <name, len>, all three callers of write_name() passes a
NUL-terminated string and its true length, so this patch makes
"len" unused.
- For <prefix, prefix_len>, prefix could be a string that is longer
than empty while prefix_len could be 0 when "--full-name" option
is used. This is fixed by checking prefix_len in write_name()
and calling write_name_quoted_relative() with NULL when
prefix_len is set to 0. Again, this makes "prefix_len" given to
write_name_quoted_relative() unused, without introducing a bug.
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-06-25 23:53:44 +08:00
|
|
|
name = relative_path(name, prefix, &sb);
|
2010-06-03 21:36:31 +08:00
|
|
|
write_name_quoted(name, fp, terminator);
|
|
|
|
|
|
|
|
strbuf_release(&sb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* quote path as relative to the given prefix */
|
2020-09-11 01:01:54 +08:00
|
|
|
char *quote_path(const char *in, const char *prefix, struct strbuf *out, unsigned flags)
|
2010-06-03 21:36:31 +08:00
|
|
|
{
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
quote.c: substitute path_relative with relative_path
Substitute the function path_relative in quote.c with the function
relative_path. Function relative_path can be treated as an enhanced
and more robust version of path_relative.
Outputs of path_relative and it's replacement (relative_path) are the
same for the following cases:
path prefix output of path_relative output of relative_path
======== ========= ======================= =======================
/a/b/c/ /a/b/ c/ c/
/a/b/c /a/b/ c c
/a/ /a/b/ ../ ../
/ /a/b/ ../../ ../../
/a/c /a/b/ ../c ../c
/x/y /a/b/ ../../x/y ../../x/y
a/b/c/ a/b/ c/ c/
a/ a/b/ ../ ../
x/y a/b/ ../../x/y ../../x/y
/a/b (empty) /a/b /a/b
/a/b (null) /a/b /a/b
a/b (empty) a/b a/b
a/b (null) a/b a/b
But if both of the path and the prefix are the same, or the returned
relative path should be the current directory, the outputs of both
functions are different. Function relative_path returns "./", while
function path_relative returns empty string.
path prefix output of path_relative output of relative_path
======== ========= ======================= =======================
/a/b/ /a/b/ (empty) ./
a/b/ a/b/ (empty) ./
(empty) (null) (empty) ./
(empty) (empty) (empty) ./
But the callers of path_relative can handle such cases, or never
encounter this issue at all, because:
* In function quote_path_relative, if the output of path_relative is
empty, append "./" to it, like:
if (!out->len)
strbuf_addstr(out, "./");
* Another caller is write_name_quoted_relative, which is only used
by builtin/ls-files.c. git-ls-files only show files, so path of
files will never be identical with the prefix of a directory.
The following differences show that path_relative does not handle
extra slashes properly:
path prefix output of path_relative output of relative_path
======== ========= ======================= =======================
/a//b//c/ //a/b// ../../../../a//b//c/ c/
a/b//c a//b ../b//c c
And if prefix has no trailing slash, path_relative does not work
properly either. But since prefix always has a trailing slash, it's
not a problem.
path prefix output of path_relative output of relative_path
======== ========= ======================= =======================
/a/b/c/ /a/b b/c/ c/
/a/b /a/b b ./
/a/b/ /a/b b/ ./
/a /a/b/ ../../a ../
a/b/c/ a/b b/c/ c/
a/b/ a/b b/ ./
a a/b ../a ../
x/y a/b/ ../x/y ../../x/y
a/c a/b c ../c
/a/ /a/b (empty) ../
(empty) /a/b ../../ ./
One tricky part in this conversion is write_name() function in
ls-files.c. It takes a counted string, <name, len>, that is to be
made relative to <prefix, prefix_len> and then quoted. Because
write_name_quoted_relative() still takes these two parameters as
counted string, but ignores the count and treat these two as
NUL-terminated strings, this conversion needs to be audited for its
callers:
- For <name, len>, all three callers of write_name() passes a
NUL-terminated string and its true length, so this patch makes
"len" unused.
- For <prefix, prefix_len>, prefix could be a string that is longer
than empty while prefix_len could be 0 when "--full-name" option
is used. This is fixed by checking prefix_len in write_name()
and calling write_name_quoted_relative() with NULL when
prefix_len is set to 0. Again, this makes "prefix_len" given to
write_name_quoted_relative() unused, without introducing a bug.
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-06-25 23:53:44 +08:00
|
|
|
const char *rel = relative_path(in, prefix, &sb);
|
quote_path: code clarification
The implementation we moved from wt-status to enclose a pathname
that has a SP in it inside a dq-pair is a bit convoluted. It lets
quote_c_style_counted() do its escaping and then
(1) if the input string got escaped, which is checked by seeing if
the result begins with a double-quote, declare that we are
done. If there wasn't any SP in the input, that is OK, and if
there was, the result is quoted already so it is OK, too.
(2) if the input string did not get escaped, and the result has SP
in it, enclose the whole thing in a dq-pair ourselves.
Instead we can scan the path upfront to see if the input has SP in
it. If so, we tell quote_c_style_counted() not to enclose its
output in a dq-pair, and we add a dq-pair ourselves. Whether the
input had bytes that quote_c_style_counted() uses backslash quoting,
this would give us a desired quoted string. If the input does not
have SP in it, we just let quote_c_style_counted() do its thing as
usual, which would enclose the result in a dq-pair only when needed.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-09-11 01:01:56 +08:00
|
|
|
int force_dq = ((flags & QUOTE_PATH_QUOTE_SP) && strchr(rel, ' '));
|
|
|
|
|
2010-06-03 21:36:31 +08:00
|
|
|
strbuf_reset(out);
|
2008-03-07 10:30:58 +08:00
|
|
|
|
quote_path: code clarification
The implementation we moved from wt-status to enclose a pathname
that has a SP in it inside a dq-pair is a bit convoluted. It lets
quote_c_style_counted() do its escaping and then
(1) if the input string got escaped, which is checked by seeing if
the result begins with a double-quote, declare that we are
done. If there wasn't any SP in the input, that is OK, and if
there was, the result is quoted already so it is OK, too.
(2) if the input string did not get escaped, and the result has SP
in it, enclose the whole thing in a dq-pair ourselves.
Instead we can scan the path upfront to see if the input has SP in
it. If so, we tell quote_c_style_counted() not to enclose its
output in a dq-pair, and we add a dq-pair ourselves. Whether the
input had bytes that quote_c_style_counted() uses backslash quoting,
this would give us a desired quoted string. If the input does not
have SP in it, we just let quote_c_style_counted() do its thing as
usual, which would enclose the result in a dq-pair only when needed.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-09-11 01:01:56 +08:00
|
|
|
/*
|
|
|
|
* If the caller wants us to enclose the output in a dq-pair
|
|
|
|
* whether quote_c_style_counted() needs to, we do it ourselves
|
|
|
|
* and tell quote_c_style_counted() not to.
|
|
|
|
*/
|
|
|
|
if (force_dq)
|
2020-09-11 01:01:55 +08:00
|
|
|
strbuf_addch(out, '"');
|
2020-09-11 01:01:59 +08:00
|
|
|
quote_c_style_counted(rel, strlen(rel), out, NULL,
|
|
|
|
force_dq ? CQUOTE_NODQ : 0);
|
quote_path: code clarification
The implementation we moved from wt-status to enclose a pathname
that has a SP in it inside a dq-pair is a bit convoluted. It lets
quote_c_style_counted() do its escaping and then
(1) if the input string got escaped, which is checked by seeing if
the result begins with a double-quote, declare that we are
done. If there wasn't any SP in the input, that is OK, and if
there was, the result is quoted already so it is OK, too.
(2) if the input string did not get escaped, and the result has SP
in it, enclose the whole thing in a dq-pair ourselves.
Instead we can scan the path upfront to see if the input has SP in
it. If so, we tell quote_c_style_counted() not to enclose its
output in a dq-pair, and we add a dq-pair ourselves. Whether the
input had bytes that quote_c_style_counted() uses backslash quoting,
this would give us a desired quoted string. If the input does not
have SP in it, we just let quote_c_style_counted() do its thing as
usual, which would enclose the result in a dq-pair only when needed.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-09-11 01:01:56 +08:00
|
|
|
if (force_dq)
|
|
|
|
strbuf_addch(out, '"');
|
|
|
|
strbuf_release(&sb);
|
2020-09-11 01:01:55 +08:00
|
|
|
|
2008-03-07 10:30:58 +08:00
|
|
|
return out->buf;
|
|
|
|
}
|
|
|
|
|
2005-10-15 12:54:47 +08:00
|
|
|
/*
|
|
|
|
* C-style name unquoting.
|
|
|
|
*
|
2007-09-20 06:42:14 +08:00
|
|
|
* Quoted should point at the opening double quote.
|
|
|
|
* + Returns 0 if it was able to unquote the string properly, and appends the
|
|
|
|
* result in the strbuf `sb'.
|
|
|
|
* + Returns -1 in case of error, and doesn't touch the strbuf. Though note
|
|
|
|
* that this function will allocate memory in the strbuf, so calling
|
|
|
|
* strbuf_release is mandatory whichever result unquote_c_style returns.
|
|
|
|
*
|
|
|
|
* Updates endp pointer to point at one past the ending double quote if given.
|
2005-10-15 12:54:47 +08:00
|
|
|
*/
|
2007-09-20 06:42:14 +08:00
|
|
|
int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
|
2005-10-15 12:54:47 +08:00
|
|
|
{
|
2007-09-20 06:42:14 +08:00
|
|
|
size_t oldlen = sb->len, len;
|
|
|
|
int ch, ac;
|
2005-10-15 12:54:47 +08:00
|
|
|
|
|
|
|
if (*quoted++ != '"')
|
2007-09-20 06:42:14 +08:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
len = strcspn(quoted, "\"\\");
|
|
|
|
strbuf_add(sb, quoted, len);
|
|
|
|
quoted += len;
|
2005-10-15 12:54:47 +08:00
|
|
|
|
2007-09-20 06:42:14 +08:00
|
|
|
switch (*quoted++) {
|
|
|
|
case '"':
|
|
|
|
if (endp)
|
2008-03-07 05:28:19 +08:00
|
|
|
*endp = quoted;
|
2007-09-20 06:42:14 +08:00
|
|
|
return 0;
|
|
|
|
case '\\':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ((ch = *quoted++)) {
|
|
|
|
case 'a': ch = '\a'; break;
|
|
|
|
case 'b': ch = '\b'; break;
|
|
|
|
case 'f': ch = '\f'; break;
|
|
|
|
case 'n': ch = '\n'; break;
|
|
|
|
case 'r': ch = '\r'; break;
|
|
|
|
case 't': ch = '\t'; break;
|
|
|
|
case 'v': ch = '\v'; break;
|
|
|
|
|
|
|
|
case '\\': case '"':
|
|
|
|
break; /* verbatim */
|
|
|
|
|
|
|
|
/* octal values with first digit over 4 overflow */
|
|
|
|
case '0': case '1': case '2': case '3':
|
2005-10-15 12:54:47 +08:00
|
|
|
ac = ((ch - '0') << 6);
|
2007-09-20 06:42:14 +08:00
|
|
|
if ((ch = *quoted++) < '0' || '7' < ch)
|
|
|
|
goto error;
|
2005-10-15 12:54:47 +08:00
|
|
|
ac |= ((ch - '0') << 3);
|
2007-09-20 06:42:14 +08:00
|
|
|
if ((ch = *quoted++) < '0' || '7' < ch)
|
|
|
|
goto error;
|
2005-10-15 12:54:47 +08:00
|
|
|
ac |= (ch - '0');
|
|
|
|
ch = ac;
|
|
|
|
break;
|
|
|
|
default:
|
2007-09-20 06:42:14 +08:00
|
|
|
goto error;
|
2005-10-15 12:54:47 +08:00
|
|
|
}
|
2007-09-20 06:42:14 +08:00
|
|
|
strbuf_addch(sb, ch);
|
2005-10-15 12:54:47 +08:00
|
|
|
}
|
|
|
|
|
2007-09-20 06:42:14 +08:00
|
|
|
error:
|
|
|
|
strbuf_setlen(sb, oldlen);
|
|
|
|
return -1;
|
2005-10-15 12:54:47 +08:00
|
|
|
}
|
|
|
|
|
2006-09-16 04:30:02 +08:00
|
|
|
/* quoting as a string literal for other languages */
|
|
|
|
|
2013-07-30 16:31:25 +08:00
|
|
|
void perl_quote_buf(struct strbuf *sb, const char *src)
|
2006-09-16 04:30:02 +08:00
|
|
|
{
|
|
|
|
const char sq = '\'';
|
|
|
|
const char bq = '\\';
|
|
|
|
char c;
|
|
|
|
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, sq);
|
2006-09-16 04:30:02 +08:00
|
|
|
while ((c = *src++)) {
|
|
|
|
if (c == sq || c == bq)
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, bq);
|
|
|
|
strbuf_addch(sb, c);
|
2006-09-16 04:30:02 +08:00
|
|
|
}
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, sq);
|
2006-09-16 04:30:02 +08:00
|
|
|
}
|
|
|
|
|
2021-07-26 11:26:48 +08:00
|
|
|
void perl_quote_buf_with_len(struct strbuf *sb, const char *src, size_t len)
|
|
|
|
{
|
|
|
|
const char sq = '\'';
|
|
|
|
const char bq = '\\';
|
|
|
|
const char *c = src;
|
|
|
|
const char *end = src + len;
|
|
|
|
|
|
|
|
strbuf_addch(sb, sq);
|
|
|
|
while (c != end) {
|
|
|
|
if (*c == sq || *c == bq)
|
|
|
|
strbuf_addch(sb, bq);
|
|
|
|
strbuf_addch(sb, *c);
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
strbuf_addch(sb, sq);
|
|
|
|
}
|
|
|
|
|
2013-07-30 16:31:25 +08:00
|
|
|
void python_quote_buf(struct strbuf *sb, const char *src)
|
2006-09-16 04:30:02 +08:00
|
|
|
{
|
|
|
|
const char sq = '\'';
|
|
|
|
const char bq = '\\';
|
|
|
|
const char nl = '\n';
|
|
|
|
char c;
|
|
|
|
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, sq);
|
2006-09-16 04:30:02 +08:00
|
|
|
while ((c = *src++)) {
|
|
|
|
if (c == nl) {
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, bq);
|
|
|
|
strbuf_addch(sb, 'n');
|
2006-09-16 04:30:02 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == sq || c == bq)
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, bq);
|
|
|
|
strbuf_addch(sb, c);
|
2006-09-16 04:30:02 +08:00
|
|
|
}
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, sq);
|
2006-09-16 04:30:02 +08:00
|
|
|
}
|
2007-01-28 15:39:13 +08:00
|
|
|
|
2013-07-30 16:31:25 +08:00
|
|
|
void tcl_quote_buf(struct strbuf *sb, const char *src)
|
2007-01-28 15:39:13 +08:00
|
|
|
{
|
|
|
|
char c;
|
|
|
|
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, '"');
|
2007-01-28 15:39:13 +08:00
|
|
|
while ((c = *src++)) {
|
|
|
|
switch (c) {
|
|
|
|
case '[': case ']':
|
|
|
|
case '{': case '}':
|
|
|
|
case '$': case '\\': case '"':
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, '\\');
|
consistently use "fallthrough" comments in switches
Gcc 7 adds -Wimplicit-fallthrough, which can warn when a
switch case falls through to the next case. The general idea
is that the compiler can't tell if this was intentional or
not, so you should annotate any intentional fall-throughs as
such, leaving it to complain about any unannotated ones.
There's a GNU __attribute__ which can be used for
annotation, but of course we'd have to #ifdef it away on
non-gcc compilers. Gcc will also recognize
specially-formatted comments, which matches our current
practice. Let's extend that practice to all of the
unannotated sites (which I did look over and verify that
they were behaving as intended).
Ideally in each case we'd actually give some reasons in the
comment about why we're falling through, or what we're
falling through to. And gcc does support that with
-Wimplicit-fallthrough=2, which relaxes the comment pattern
matching to anything that contains "fallthrough" (or a
variety of spelling variants). However, this isn't the
default for -Wimplicit-fallthrough, nor for -Wextra. In the
name of simplicity, it's probably better for us to support
the default level, which requires "fallthrough" to be the
only thing in the comment (modulo some window dressing like
"else" and some punctuation; see the gcc manual for the
complete set of patterns).
This patch suppresses all warnings due to
-Wimplicit-fallthrough. We might eventually want to add that
to the DEVELOPER Makefile knob, but we should probably wait
until gcc 7 is more widely adopted (since earlier versions
will complain about the unknown warning type).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-21 14:25:41 +08:00
|
|
|
/* fallthrough */
|
2007-01-28 15:39:13 +08:00
|
|
|
default:
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, c);
|
2007-01-28 15:39:13 +08:00
|
|
|
break;
|
|
|
|
case '\f':
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addstr(sb, "\\f");
|
2007-01-28 15:39:13 +08:00
|
|
|
break;
|
|
|
|
case '\r':
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addstr(sb, "\\r");
|
2007-01-28 15:39:13 +08:00
|
|
|
break;
|
|
|
|
case '\n':
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addstr(sb, "\\n");
|
2007-01-28 15:39:13 +08:00
|
|
|
break;
|
|
|
|
case '\t':
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addstr(sb, "\\t");
|
2007-01-28 15:39:13 +08:00
|
|
|
break;
|
|
|
|
case '\v':
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addstr(sb, "\\v");
|
2007-01-28 15:39:13 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-07-30 16:31:25 +08:00
|
|
|
strbuf_addch(sb, '"');
|
2007-01-28 15:39:13 +08:00
|
|
|
}
|
2016-06-25 13:22:31 +08:00
|
|
|
|
|
|
|
void basic_regex_quote_buf(struct strbuf *sb, const char *src)
|
|
|
|
{
|
|
|
|
char c;
|
|
|
|
|
|
|
|
if (*src == '^') {
|
|
|
|
/* only beginning '^' is special and needs quoting */
|
|
|
|
strbuf_addch(sb, '\\');
|
|
|
|
strbuf_addch(sb, *src++);
|
|
|
|
}
|
|
|
|
if (*src == '*')
|
|
|
|
/* beginning '*' is not special, no quoting */
|
|
|
|
strbuf_addch(sb, *src++);
|
|
|
|
|
|
|
|
while ((c = *src++)) {
|
|
|
|
switch (c) {
|
|
|
|
case '[':
|
|
|
|
case '.':
|
|
|
|
case '\\':
|
|
|
|
case '*':
|
|
|
|
strbuf_addch(sb, '\\');
|
|
|
|
strbuf_addch(sb, c);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '$':
|
|
|
|
/* only the end '$' is special and needs quoting */
|
|
|
|
if (*src == '\0')
|
|
|
|
strbuf_addch(sb, '\\');
|
|
|
|
strbuf_addch(sb, c);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
strbuf_addch(sb, c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|