libpkgconf: fragment: rework quoting and lexing (closes #139, #153)

we now use POSIX-style quoting for all fragments.  it is our belief that this is the
most optimal behaviour for portability, because all POSIX-compliant tools require
single-quotes to be considered as literal (closes #153).

because of this, we are able to remove some hacks on the lexer side which were there
to simulate pkg-config quoting, but were basically utterly wrong (closes #139).
feature/tap-sh
William Pitcock 2017-12-11 18:25:55 -06:00
parent 1c9880a03b
commit 278a2bd667
3 changed files with 34 additions and 42 deletions

View File

@ -89,7 +89,7 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
} }
else else
{ {
if (isspace((unsigned int) *src_iter) || *src_iter == '\\') if (*src_iter == '\\')
*dst_iter++ = '\\'; *dst_iter++ = '\\';
*dst_iter++ = *src_iter; *dst_iter++ = *src_iter;

View File

@ -351,6 +351,8 @@ pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, cons
frag = calloc(sizeof(pkgconf_fragment_t), 1); frag = calloc(sizeof(pkgconf_fragment_t), 1);
frag->type = base->type; frag->type = base->type;
frag->merged = base->merged;
if (base->data != NULL)
frag->data = strdup(base->data); frag->data = strdup(base->data);
pkgconf_node_insert_tail(&frag->iter, frag, list); pkgconf_node_insert_tail(&frag->iter, frag, list);
@ -384,17 +386,18 @@ pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pk
} }
} }
static inline char * static inline bool
fragment_escape(const char *src) fragment_should_quote(const pkgconf_fragment_t *frag)
{ {
ssize_t outlen = strlen(src) + 10; const char *src;
char *out = calloc(outlen, 1);
char *dst = out;
while (*src) if (frag->data == NULL)
return false;
for (src = frag->data; *src; src++)
{ {
if (((*src < ' ') || if (((*src < ' ') ||
(*src > ' ' && *src < '$') || (*src >= (' ' + (frag->merged ? 1 : 0)) && *src < '$') ||
(*src > '$' && *src < '(') || (*src > '$' && *src < '(') ||
(*src > ')' && *src < '+') || (*src > ')' && *src < '+') ||
(*src > ':' && *src < '=') || (*src > ':' && *src < '=') ||
@ -403,23 +406,14 @@ fragment_escape(const char *src)
(*src == '`') || (*src == '`') ||
(*src > 'z' && *src < '~') || (*src > 'z' && *src < '~') ||
(*src > '~')) && *src != '\\') (*src > '~')) && *src != '\\')
*dst++ = '\\'; return true;
*dst++ = *src++;
if ((ptrdiff_t)(dst - out) + 2 > outlen)
{
outlen *= 2;
out = realloc(out, outlen);
}
} }
*dst = 0; return false;
return out;
} }
static inline size_t static inline size_t
pkgconf_fragment_len(const pkgconf_fragment_t *frag, bool escape) pkgconf_fragment_len(const pkgconf_fragment_t *frag)
{ {
size_t len = 1; size_t len = 1;
@ -428,14 +422,10 @@ pkgconf_fragment_len(const pkgconf_fragment_t *frag, bool escape)
if (frag->data != NULL) if (frag->data != NULL)
{ {
if (!escape)
len += strlen(frag->data); len += strlen(frag->data);
else
{ if (fragment_should_quote(frag))
char *tmp = fragment_escape(frag->data); len += 2;
len += strlen(tmp);
free(tmp);
}
} }
return len; return len;
@ -444,13 +434,15 @@ pkgconf_fragment_len(const pkgconf_fragment_t *frag, bool escape)
static size_t static size_t
fragment_render_len(const pkgconf_list_t *list, bool escape) fragment_render_len(const pkgconf_list_t *list, bool escape)
{ {
(void) escape;
size_t out = 1; /* trailing nul */ size_t out = 1; /* trailing nul */
pkgconf_node_t *node; pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node) PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{ {
const pkgconf_fragment_t *frag = node->data; const pkgconf_fragment_t *frag = node->data;
out += pkgconf_fragment_len(frag, escape); out += pkgconf_fragment_len(frag);
} }
return out; return out;
@ -459,6 +451,8 @@ fragment_render_len(const pkgconf_list_t *list, bool escape)
static void static void
fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape) fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape)
{ {
(void) escape;
pkgconf_node_t *node; pkgconf_node_t *node;
char *bptr = buf; char *bptr = buf;
@ -468,10 +462,14 @@ fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool e
{ {
const pkgconf_fragment_t *frag = node->data; const pkgconf_fragment_t *frag = node->data;
size_t buf_remaining = buflen - (bptr - buf); size_t buf_remaining = buflen - (bptr - buf);
bool should_quote = fragment_should_quote(frag);
if (pkgconf_fragment_len(frag, escape) > buf_remaining) if (pkgconf_fragment_len(frag) > buf_remaining)
break; break;
if (should_quote)
*bptr++ = '\'';
if (frag->type) if (frag->type)
{ {
*bptr++ = '-'; *bptr++ = '-';
@ -479,16 +477,10 @@ fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool e
} }
if (frag->data) if (frag->data)
{
if (!escape)
bptr += pkgconf_strlcpy(bptr, frag->data, buf_remaining); bptr += pkgconf_strlcpy(bptr, frag->data, buf_remaining);
else
{ if (should_quote)
char *tmp = fragment_escape(frag->data); *bptr++ = '\'';
bptr += pkgconf_strlcpy(bptr, tmp, buf_remaining);
free(tmp);
}
}
*bptr++ = ' '; *bptr++ = ' ';
} }

View File

@ -203,7 +203,7 @@ fragment_quoting_7_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \ atf_check \
-o inline:"-Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\\ world \n" \ -o inline:"-Dhello=10 -Dworld=+32 '-DDEFINED_FROM_PKG_CONFIG=hello world' \n" \
pkgconf --cflags fragment-quoting-7 pkgconf --cflags fragment-quoting-7
} }