aboutsummaryrefslogtreecommitdiff
path: root/libpkgconf/fragment.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpkgconf/fragment.c')
-rw-r--r--libpkgconf/fragment.c171
1 files changed, 98 insertions, 73 deletions
diff --git a/libpkgconf/fragment.c b/libpkgconf/fragment.c
index 7576db7..78a3463 100644
--- a/libpkgconf/fragment.c
+++ b/libpkgconf/fragment.c
@@ -173,6 +173,7 @@ pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const
free(parent->data);
parent->data = newdata;
+ parent->merged = true;
/* use a copy operation to force a dedup */
pkgconf_node_delete(&parent->iter, list);
@@ -350,7 +351,9 @@ pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, cons
frag = calloc(sizeof(pkgconf_fragment_t), 1);
frag->type = base->type;
- frag->data = strdup(base->data);
+ frag->merged = base->merged;
+ if (base->data != NULL)
+ frag->data = strdup(base->data);
pkgconf_node_insert_tail(&frag->iter, frag, list);
}
@@ -383,17 +386,18 @@ pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pk
}
}
-static inline char *
-fragment_escape(const char *src)
+static inline bool
+fragment_should_quote(const pkgconf_fragment_t *frag)
{
- ssize_t outlen = strlen(src) + 10;
- char *out = calloc(outlen, 1);
- char *dst = out;
+ const char *src;
- while (*src)
+ if (frag->data == NULL)
+ return false;
+
+ for (src = frag->data; *src; src++)
{
if (((*src < ' ') ||
- (*src > ' ' && *src < '$') ||
+ (*src >= (' ' + (frag->merged ? 1 : 0)) && *src < '$') ||
(*src > '$' && *src < '(') ||
(*src > ')' && *src < '+') ||
(*src > ':' && *src < '=') ||
@@ -402,23 +406,14 @@ fragment_escape(const char *src)
(*src == '`') ||
(*src > 'z' && *src < '~') ||
(*src > '~')) && *src != '\\')
- *dst++ = '\\';
-
- *dst++ = *src++;
-
- if ((ptrdiff_t)(dst - out) + 2 > outlen)
- {
- outlen *= 2;
- out = realloc(out, outlen);
- }
+ return true;
}
- *dst = 0;
- return out;
+ return false;
}
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;
@@ -427,62 +422,37 @@ pkgconf_fragment_len(const pkgconf_fragment_t *frag, bool escape)
if (frag->data != NULL)
{
- if (!escape)
- len += strlen(frag->data);
- else
- {
- char *tmp = fragment_escape(frag->data);
- len += strlen(tmp);
- free(tmp);
- }
+ len += strlen(frag->data);
+
+ if (fragment_should_quote(frag))
+ len += 2;
}
return len;
}
-/*
- * !doc
- *
- * .. c:function:: size_t pkgconf_fragment_render_len(const pkgconf_list_t *list)
- *
- * Calculates the required memory to store a `fragment list` when rendered as a string.
- *
- * :param pkgconf_list_t* list: The `fragment list` being rendered.
- * :param bool escape: Whether or not to escape special shell characters.
- * :return: the amount of bytes required to represent the `fragment list` when rendered
- * :rtype: size_t
- */
-size_t
-pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape)
+static size_t
+fragment_render_len(const pkgconf_list_t *list, bool escape)
{
+ (void) escape;
+
size_t out = 1; /* trailing nul */
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
const pkgconf_fragment_t *frag = node->data;
- out += pkgconf_fragment_len(frag, escape);
+ out += pkgconf_fragment_len(frag);
}
return out;
}
-/*
- * !doc
- *
- * .. c:function:: void pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen)
- *
- * Renders a `fragment list` into a buffer.
- *
- * :param pkgconf_list_t* list: The `fragment list` being rendered.
- * :param char* buf: The buffer to render the fragment list into.
- * :param size_t buflen: The length of the buffer.
- * :param bool escape: Whether or not to escape special shell characters.
- * :return: nothing
- */
-void
-pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape)
+static void
+fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape)
{
+ (void) escape;
+
pkgconf_node_t *node;
char *bptr = buf;
@@ -492,10 +462,14 @@ pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen
{
const pkgconf_fragment_t *frag = node->data;
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;
+ if (should_quote)
+ *bptr++ = '\'';
+
if (frag->type)
{
*bptr++ = '-';
@@ -503,16 +477,10 @@ pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen
}
if (frag->data)
- {
- if (!escape)
- bptr += pkgconf_strlcpy(bptr, frag->data, buf_remaining);
- else
- {
- char *tmp = fragment_escape(frag->data);
- bptr += pkgconf_strlcpy(bptr, tmp, buf_remaining);
- free(tmp);
- }
- }
+ bptr += pkgconf_strlcpy(bptr, frag->data, buf_remaining);
+
+ if (should_quote)
+ *bptr++ = '\'';
*bptr++ = ' ';
}
@@ -520,6 +488,60 @@ pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen
*bptr = '\0';
}
+static const pkgconf_fragment_render_ops_t default_render_ops = {
+ .render_len = fragment_render_len,
+ .render_buf = fragment_render_buf
+};
+
+/*
+ * !doc
+ *
+ * .. c:function:: size_t pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
+ *
+ * Calculates the required memory to store a `fragment list` when rendered as a string.
+ *
+ * :param pkgconf_list_t* list: The `fragment list` being rendered.
+ * :param bool escape: Whether or not to escape special shell characters (deprecated).
+ * :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
+ * :return: the amount of bytes required to represent the `fragment list` when rendered
+ * :rtype: size_t
+ */
+size_t
+pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
+{
+ (void) escape;
+
+ ops = ops != NULL ? ops : &default_render_ops;
+ return ops->render_len(list, true);
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: void pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops)
+ *
+ * Renders a `fragment list` into a buffer.
+ *
+ * :param pkgconf_list_t* list: The `fragment list` being rendered.
+ * :param char* buf: The buffer to render the fragment list into.
+ * :param size_t buflen: The length of the buffer.
+ * :param bool escape: Whether or not to escape special shell characters (deprecated).
+ * :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
+ * :return: nothing
+ */
+void
+pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops)
+{
+ (void) escape;
+
+ ops = ops != NULL ? ops : &default_render_ops;
+
+ /*
+ * The function must not return a value (issue #162 is reported).
+ */
+ ops->render_buf(list, buf, buflen, true);
+}
+
/*
* !doc
*
@@ -528,17 +550,20 @@ pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen
* Allocate memory and render a `fragment list` into it.
*
* :param pkgconf_list_t* list: The `fragment list` being rendered.
- * :param bool escape: Whether or not to escape special shell characters.
+ * :param bool escape: Whether or not to escape special shell characters (deprecated).
+ * :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
* :return: An allocated string containing the rendered `fragment list`.
* :rtype: char *
*/
char *
-pkgconf_fragment_render(const pkgconf_list_t *list, bool escape)
+pkgconf_fragment_render(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
{
- size_t buflen = pkgconf_fragment_render_len(list, escape);
+ (void) escape;
+
+ size_t buflen = pkgconf_fragment_render_len(list, true, ops);
char *buf = calloc(1, buflen);
- pkgconf_fragment_render_buf(list, buf, buflen, escape);
+ pkgconf_fragment_render_buf(list, buf, buflen, true, ops);
return buf;
}