[build-path-prefix-map-spec] 01/02: Improve the C example
Ximin Luo
infinity0 at debian.org
Fri Apr 7 16:45:49 UTC 2017
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch master
in repository build-path-prefix-map-spec.
commit 905a0174659228e12499c3119428e70ed5c1a37d
Author: Ximin Luo <infinity0 at debian.org>
Date: Sat Mar 25 13:29:49 2017 -0400
Improve the C example
- Rewind properly when parsing fails
- Only match on path boundaries (algorithm #2 in the spec, currently up for
discussion to replace #1).
- Get rid of prefix_maps and the max_replace business, instead
provide a remap_prefix_alloca macro for dynamic stack allocation.
- Various style fixes
---
consume/Makefile | 4 +-
consume/pecsplit.c | 45 ++++++++----
consume/prefix_map.h | 199 +++++++++++++++++++++++++++++++--------------------
3 files changed, 156 insertions(+), 92 deletions(-)
diff --git a/consume/Makefile b/consume/Makefile
index 8fa0176..8074765 100644
--- a/consume/Makefile
+++ b/consume/Makefile
@@ -30,7 +30,7 @@ $(foreach format,$(ALL_FORMATS),$(eval $(call find_testcases,$(format).1,env)))
all: $(ALL_SOURCE:%=%.out)
%.c.out: %.c prefix_map.h
- $(CC) -std=c11 -Werror -o "$@" "$<"
+ $(CC) -std=c11 -Werror -g -o "$@" "$<"
%.rs.out: %.rs %.c.out
# TODO: hack to avoid failing on Debian jessie, which is running on jenkins
@@ -38,7 +38,7 @@ all: $(ALL_SOURCE:%=%.out)
if [ -f /etc/debian_version -a "$$(echo "$$(cat /etc/debian_version) < 9.0" | bc)" -eq 1 ]; then \
cp "$*.c.out" "$@"; \
else \
- $(RUSTC) -W warnings -o "$@" "$<"; \
+ $(RUSTC) -W warnings -g -o "$@" "$<"; \
fi
.PHONY: check testcases-rst
diff --git a/consume/pecsplit.c b/consume/pecsplit.c
index d62c767..369e797 100644
--- a/consume/pecsplit.c
+++ b/consume/pecsplit.c
@@ -3,8 +3,11 @@
/** Parsing the variable. */
/* For Applying the variable, and Main program, see prefix_map.h. */
+/* Parse a single part of a single prefix-map pair.
+
+ Returns 0 on failure and 1 on success. */
int
-unquote (char *src)
+prefix_map_parse_unquote (char *src)
{
for (char *dest = src; 0 != (*dest = *src); ++dest, ++src)
switch (*src)
@@ -31,39 +34,55 @@ unquote (char *src)
return 1;
}
-/* Returns 0 on failure and 1 on success. */
+/* Parse a single prefix-map.
+
+ Returns 0 on failure and 1 on success. */
int
-parse_prefix_map (char *arg, struct prefix_maps *maps)
+prefix_map_parse1 (struct prefix_map **map_head, char *arg)
{
char *p;
p = strchr (arg, '=');
if (!p)
return 0;
*p = '\0';
- if (!unquote (arg))
+ if (!prefix_map_parse_unquote (arg))
return 0;
p++;
- if (!unquote (p))
+ if (!prefix_map_parse_unquote (p))
return 0;
- return add_prefix_map (arg, p, maps);
+ return prefix_map_push (map_head, arg, p);
}
-/* Returns 0 on failure and 1 on success. */
+/* Parse a prefix-map according to the BUILD_PATH_PREFIX_MAP standard.
+
+ The input string value is of the form
+
+ dst[0]=src[0]:dst[1]=src[1]...
+
+ Every dst[i] and src[i] has had "%", "=" and ":" characters replaced with
+ "%#", "%+", and "%." respectively; this function reverses this replacement.
+
+ Rightmost entries are stored at the head of the parsed structure.
+
+ Returns 0 on failure and 1 on success. */
int
-parse_prefix_maps (const char *arg, struct prefix_maps *maps)
+prefix_map_parse (struct prefix_map **map_head, const char *arg)
{
+ struct prefix_map *old_head = *map_head;
+
size_t len = strlen (arg);
char *copy = (char *) alloca (len + 1);
memcpy (copy, arg, len + 1); // strtok modifies the string so we have to copy it
- char *sep = ":", *end;
- char *tok = strtok_r (copy, sep, &end);
+ const char *sep = ":";
+ char *end, *tok = strtok_r (copy, sep, &end);
while (tok != NULL)
{
- if (!parse_prefix_map (tok, maps))
+ if (!prefix_map_parse1 (map_head, tok))
{
- fprintf (stderr, "invalid value for prefix-map: '%s'\n", arg);
+ fprintf (stderr, "invalid value for prefix-map: '%s'; rewinding to: %p\n", arg, old_head);
+ prefix_map_pop_until (map_head, old_head);
return 0;
}
@@ -76,5 +95,5 @@ parse_prefix_maps (const char *arg, struct prefix_maps *maps)
int
main (int argc, char *argv[])
{
- return generic_main (parse_prefix_maps, argc, argv);
+ return generic_main (prefix_map_parse, argc, argv);
}
diff --git a/consume/prefix_map.h b/consume/prefix_map.h
index cf2ac23..4a0a3a1 100644
--- a/consume/prefix_map.h
+++ b/consume/prefix_map.h
@@ -20,6 +20,21 @@ xstrdup (const char *s)
return (char *) memcpy (ret, s, len);
}
+/* Some path parsing primitives, basically also copied from GCC. */
+
+#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__)
+# define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c)
+#else /* not DOSish */
+# define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c)
+#endif
+
+#define IS_DIR_SEPARATOR_1(dos_based, c) \
+ (((c) == '/') \
+ || (((c) == '\\') && (dos_based)))
+
+#define IS_DOS_DIR_SEPARATOR(c) IS_DIR_SEPARATOR_1 (1, c)
+#define IS_UNIX_DIR_SEPARATOR(c) IS_DIR_SEPARATOR_1 (0, c)
+
/** Applying the variable */
struct prefix_map
@@ -31,23 +46,16 @@ struct prefix_map
struct prefix_map *next;
};
-struct prefix_maps
-{
- struct prefix_map *head;
- size_t max_replace;
-};
+/* Push a new mapping.
-/* Add a new mapping.
- *
- * The input strings are duplicated and a new prefix_map struct is allocated.
- * Ownership of the duplicates, as well as the new prefix_map, is the same as
- * the owner of the overall prefix_maps struct.
- *
- * Returns 0 on failure and 1 on success.
- */
+ The input strings are duplicated and a new prefix_map struct is allocated.
+ Ownership of the duplicates, as well as the new prefix_map, is the same as
+ the ownership of the old struct.
+
+ Returns 0 on failure and 1 on success. */
int
-add_prefix_map (const char *new_prefix, const char *old_prefix,
- struct prefix_maps *maps)
+prefix_map_push (struct prefix_map **map_head,
+ const char *new_prefix, const char *old_prefix)
{
struct prefix_map *map = XNEW (struct prefix_map);
if (!map)
@@ -63,12 +71,8 @@ add_prefix_map (const char *new_prefix, const char *old_prefix,
goto rewind_2;
map->new_len = strlen (new_prefix);
- map->next = maps->head;
- maps->head = map;
-
- if (map->new_len > maps->max_replace)
- maps->max_replace = map->new_len;
-
+ map->next = *map_head;
+ *map_head = map;
return 1;
rewind_2:
@@ -79,18 +83,16 @@ rewind_0:
return 0;
}
+/* Pop a prefix map.
-/* Clear all mappings.
- *
- * All child structs of [maps] are freed, but it itself is not freed.
- */
+ Everything up to but excluding the given OLD_HEAD is freed. */
void
-clear_prefix_maps (struct prefix_maps *maps)
+prefix_map_pop_until (struct prefix_map **map_head, struct prefix_map *old_head)
{
struct prefix_map *map;
struct prefix_map *next;
- for (map = maps->head; map; map = next)
+ for (map = *map_head; map != old_head; map = next)
{
free ((void *) map->old_prefix);
free ((void *) map->new_prefix);
@@ -98,61 +100,103 @@ clear_prefix_maps (struct prefix_maps *maps)
free (map);
}
- maps->max_replace = 0;
+ *map_head = map;
}
+/* Clear all mappings.
-/* Private function, assumes new_name is wide enough to hold the remapped name. */
-const char *
-_apply_prefix_map (const char *old_name, char *new_name,
- struct prefix_map *map_head)
+ All child structs of MAP_HEAD are freed. */
+void
+prefix_map_clear (struct prefix_map **map_head)
{
- struct prefix_map *map;
- const char *name;
+ prefix_map_pop_until (map_head, NULL);
+}
- for (map = map_head; map; map = map->next)
- if (strncmp (old_name, map->old_prefix, map->old_len) == 0)
- break;
- if (!map)
- return old_name;
- name = old_name + map->old_len;
+/* Find a mapping suitable for the given OLD_NAME in the linked list MAP.\
+
+ If a mapping is found, writes a pointer to the non-matching suffix part of
+ OLD_NAME in SUFFIX, and its length in SUF_LEN.
+
+ Returns NULL if there was no suitable mapping. */
+struct prefix_map *
+prefix_map_find (struct prefix_map *map, const char *old_name,
+ const char **suffix, size_t *suf_len)
+{
+ size_t len;
+
+ for (; map; map = map->next)
+ {
+ len = map->old_len;
+ /* Ignore trailing path separators at the end of old_prefix */
+ while (len > 0 && IS_DIR_SEPARATOR (map->old_prefix[len-1])) len--;
+ /* Check if old_name matches old_prefix at a path component boundary */
+ if (! strncmp (old_name, map->old_prefix, len)
+ && (IS_DIR_SEPARATOR (old_name[len])
+ || old_name[len] == '\0'))
+ {
+ *suf_len = strlen (*suffix = old_name + len);
+ break;
+ }
+ }
+
+ return map;
+}
+
+/* Prepend a prefix map before a given SUFFIX.
+
+ The remapped name is written to NEW_NAME and returned as a const pointer. No
+ allocations are performed; the caller must ensure it can hold at least
+ MAP->NEW_LEN + SUF_LEN + 1 characters. */
+const char *
+prefix_map_prepend (struct prefix_map *map, char *new_name,
+ const char *suffix, size_t suf_len)
+{
memcpy (new_name, map->new_prefix, map->new_len);
- memcpy (new_name + map->new_len, name, strlen (name) + 1);
+ memcpy (new_name + map->new_len, suffix, suf_len + 1);
return new_name;
}
+/* Remap a filename.
+
+ Returns OLD_NAME unchanged if there was no remapping, otherwise returns a
+ pointer to newly-allocated memory for the remapped filename. The memory is
+ allocated by the given ALLOC function, which also determines who is
+ responsible for freeing it. */
+#define prefix_map_remap_alloc_(map_head, old_name, alloc) \
+ __extension__ \
+ ({ \
+ const char *__suffix; \
+ size_t __suf_len; \
+ struct prefix_map *__map; \
+ (__map = prefix_map_find ((map_head), (old_name), &__suffix, &__suf_len)) \
+ ? prefix_map_prepend (__map, \
+ (char *) alloc (__map->new_len + __suf_len + 1), \
+ __suffix, __suf_len) \
+ : (old_name); \
+ })
/* Remap a filename.
- *
- * This function does not consume nor take ownership of filename; the caller is
- * responsible for freeing it, if and only if it was already responsible for
- * freeing it before the call.
- *
- * It allocates new memory only in the case that a mapping was made. That is,
- * if and only if filename != return-value, then the caller is responsible for
- * freeing return-value.
-*/
-const char *
-remap_prefix_alloc (const char *filename, struct prefix_maps *maps, void *(*alloc)(size_t size))
-{
- size_t maxlen = strlen (filename) + maps->max_replace + 1;
- char *newname = (char *) alloca (maxlen);
- const char *name = _apply_prefix_map (filename, newname, maps->head);
- if (name == filename)
- return filename;
+ Returns OLD_NAME unchanged if there was no remapping, otherwise returns a
+ stack-allocated pointer to the newly-remapped filename. */
+#define prefix_map_remap_alloca(map_head, old_name) \
+ prefix_map_remap_alloc_ (map_head, old_name, alloca)
- size_t len = strlen (newname) + 1;
- return (char *) memcpy (alloc (len), newname, len);
-}
+/* Remap a filename.
+ Returns OLD_NAME unchanged if there was no remapping, otherwise returns a
+ pointer to newly-allocated memory for the remapped filename. The caller is
+ then responsible for freeing it.
-/* Like remap_prefix_alloc but with the system allocator. */
+ That is, if and only if OLD_NAME != return-value, the caller is responsible
+ for freeing return-value. The owner of filename remains unchanged. */
const char *
-remap_prefix (const char *filename, struct prefix_maps *maps)
+prefix_map_remap_alloc (struct prefix_map *map_head,
+ const char *old_name,
+ void *(*alloc)(size_t size))
{
- return remap_prefix_alloc (filename, maps, malloc);
+ return prefix_map_remap_alloc_ (map_head, old_name, alloc);
}
/** Main program */
@@ -172,9 +216,9 @@ remap_prefix (const char *filename, struct prefix_maps *maps)
* Returns 1 on failure and 0 on success.
*/
int
-generic_main (int (*parse_prefix_maps) (const char *, struct prefix_maps *), int argc, char *argv[])
+generic_main (int (*prefix_map_parse) (struct prefix_map **, const char *), int argc, char *argv[])
{
- struct prefix_maps build_path_prefix_map = { NULL, 0 };
+ struct prefix_map *build_path_prefix_map = NULL;
int using_stdin = 0; // 0 = BUILD_PATH_PREFIX_MAP envvar, 1 = stdin (for afl)
char *str = NULL;
@@ -193,9 +237,9 @@ generic_main (int (*parse_prefix_maps) (const char *, struct prefix_maps *), int
str = getenv ("BUILD_PATH_PREFIX_MAP");
if (str)
- if (!parse_prefix_maps (str, &build_path_prefix_map))
+ if (!prefix_map_parse (&build_path_prefix_map, str))
{
- fprintf (stderr, "parse_prefix_maps failed\n");
+ fprintf (stderr, "parse_prefix_map failed\n");
goto err_exit;
}
@@ -207,29 +251,30 @@ generic_main (int (*parse_prefix_maps) (const char *, struct prefix_maps *), int
while (-1 != (read = getline (&str, &len_allocated, stdin)))
{
*(str + read - 1) = 0;
- printf ("%s\n", remap_prefix (str, &build_path_prefix_map));
+ // use malloc here as an example
+ const char *newarg = prefix_map_remap_alloc (build_path_prefix_map, str, malloc);
+ printf ("%s\n", newarg);
+ if (newarg != str)
+ free ((void *) newarg); // as per contract of remap_prefix_alloc()
}
+ free (str);
if (ferror (stdin))
goto err_stdin;
}
else
{
+ // using alloca, no free needed
for (int i = using_stdin ? 2 : 1; i < argc; i++)
- {
- const char *newarg = remap_prefix (argv[i], &build_path_prefix_map);
- printf ("%s\n", newarg);
- if (newarg != argv[i])
- free ((void *) newarg); // as per contract of remap_prefix()
- }
+ printf ("%s\n", prefix_map_remap_alloca (build_path_prefix_map, argv[i]));
}
- clear_prefix_maps (&build_path_prefix_map);
+ prefix_map_clear (&build_path_prefix_map);
return 0;
err_stdin:
perror ("failed to read from stdin");
err_exit:
- clear_prefix_maps (&build_path_prefix_map);
+ prefix_map_clear (&build_path_prefix_map);
return 1;
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/build-path-prefix-map-spec.git
More information about the Reproducible-commits
mailing list