aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/Makefile.in1
-rw-r--r--gdb/common/pathstuff.c50
-rw-r--r--gdb/common/pathstuff.h6
-rw-r--r--gdb/unittests/child-path-selftests.c68
5 files changed, 133 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e4f74cd..2357a40 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
2019-02-12 John Baldwin <jhb@FreeBSD.org>
+ * Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
+ unittests/child-path-selftests.c.
+ * common/pathstuff.c (child_path): New function.
+ * common/pathstuff.h (child_path): New prototype.
+ * unittests/child-path-selftests.c: New file.
+
+2019-02-12 John Baldwin <jhb@FreeBSD.org>
+
* symfile.c (find_separate_debug_file): Look for separate debug
files in debug directories under the sysroot.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index cb5b740..5614cc3 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -411,6 +411,7 @@ SUBDIR_PYTHON_CFLAGS =
SUBDIR_UNITTESTS_SRCS = \
unittests/array-view-selftests.c \
+ unittests/child-path-selftests.c \
unittests/cli-utils-selftests.c \
unittests/common-utils-selftests.c \
unittests/copy_bitwise-selftests.c \
diff --git a/gdb/common/pathstuff.c b/gdb/common/pathstuff.c
index 1167530..2b1669a 100644
--- a/gdb/common/pathstuff.c
+++ b/gdb/common/pathstuff.c
@@ -147,6 +147,56 @@ gdb_abspath (const char *path)
/* See common/pathstuff.h. */
+const char *
+child_path (const char *parent, const char *child)
+{
+ /* The child path must start with the parent path. */
+ size_t parent_len = strlen (parent);
+ if (filename_ncmp (parent, child, parent_len) != 0)
+ return NULL;
+
+ /* The parent path must be a directory and the child must contain at
+ least one component underneath the parent. */
+ const char *child_component;
+ if (IS_DIR_SEPARATOR (parent[parent_len - 1]))
+ {
+ /* The parent path ends in a directory separator, so it is a
+ directory. The first child component starts after the common
+ prefix. */
+ child_component = child + parent_len;
+ }
+ else
+ {
+ /* The parent path does not end in a directory separator. The
+ first character in the child after the common prefix must be
+ a directory separator.
+
+ Note that CHILD must hold at least parent_len characters for
+ filename_ncmp to return zero. If the character at parent_len
+ is nul due to CHILD containing the same path as PARENT, the
+ IS_DIR_SEPARATOR check will fail here. */
+ if (!IS_DIR_SEPARATOR (child[parent_len]))
+ return NULL;
+
+ /* The first child component starts after the separator after the
+ common prefix. */
+ child_component = child + parent_len + 1;
+ }
+
+ /* The child must contain at least one non-separator character after
+ the parent. */
+ while (*child_component != '\0')
+ {
+ if (!IS_DIR_SEPARATOR (*child_component))
+ return child_component;
+
+ child_component++;
+ }
+ return NULL;
+}
+
+/* See common/pathstuff.h. */
+
bool
contains_dir_separator (const char *path)
{
diff --git a/gdb/common/pathstuff.h b/gdb/common/pathstuff.h
index c264e78..67072a4 100644
--- a/gdb/common/pathstuff.h
+++ b/gdb/common/pathstuff.h
@@ -48,6 +48,12 @@ extern gdb::unique_xmalloc_ptr<char>
extern gdb::unique_xmalloc_ptr<char> gdb_abspath (const char *path);
+/* If the path in CHILD is a child of the path in PARENT, return a
+ pointer to the first component in the CHILD's pathname below the
+ PARENT. Otherwise, return NULL. */
+
+extern const char *child_path (const char *parent, const char *child);
+
/* Return whether PATH contains a directory separator character. */
extern bool contains_dir_separator (const char *path);
diff --git a/gdb/unittests/child-path-selftests.c b/gdb/unittests/child-path-selftests.c
new file mode 100644
index 0000000..4c436ef
--- /dev/null
+++ b/gdb/unittests/child-path-selftests.c
@@ -0,0 +1,68 @@
+/* Self tests for child_path for GDB, the GNU debugger.
+
+ Copyright (C) 2019 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "common/pathstuff.h"
+#include "common/selftest.h"
+
+namespace selftests {
+namespace child_path {
+
+/* Verify the result of a single child_path test. */
+
+static bool
+child_path_check (const char *parent, const char *child, const char *expected)
+{
+ const char *result = ::child_path (parent, child);
+ if (result == NULL || expected == NULL)
+ return result == expected;
+ return strcmp (result, expected) == 0;
+}
+
+/* Test child_path. */
+
+static void
+test ()
+{
+ SELF_CHECK (child_path_check ("/one", "/two", NULL));
+ SELF_CHECK (child_path_check ("/one", "/one", NULL));
+ SELF_CHECK (child_path_check ("/one", "/one/", NULL));
+ SELF_CHECK (child_path_check ("/one", "/one//", NULL));
+ SELF_CHECK (child_path_check ("/one", "/one/two", "two"));
+ SELF_CHECK (child_path_check ("/one/", "/two", NULL));
+ SELF_CHECK (child_path_check ("/one/", "/one", NULL));
+ SELF_CHECK (child_path_check ("/one/", "/one/", NULL));
+ SELF_CHECK (child_path_check ("/one/", "/one//", NULL));
+ SELF_CHECK (child_path_check ("/one/", "/one/two", "two"));
+ SELF_CHECK (child_path_check ("/one/", "/one//two", "two"));
+ SELF_CHECK (child_path_check ("/one/", "/one//two/", "two/"));
+ SELF_CHECK (child_path_check ("/one", "/onetwo", NULL));
+ SELF_CHECK (child_path_check ("/one", "/onetwo/three", NULL));
+}
+
+}
+}
+
+void
+_initialize_child_path_selftests ()
+{
+ selftests::register_test ("child_path",
+ selftests::child_path::test);
+}
+