[tip:perf/core] tools lib: Move argv_{split,free} from tools/perf/util/

From: tip-bot for Arnaldo Carvalho de Melo
Date: Wed Jul 03 2019 - 10:27:29 EST


Commit-ID: 9c10548c42219e961279826c2763a0e32dc056b9
Gitweb: https://git.kernel.org/tip/9c10548c42219e961279826c2763a0e32dc056b9
Author: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
AuthorDate: Wed, 26 Jun 2019 15:27:58 -0300
Committer: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
CommitDate: Mon, 1 Jul 2019 22:50:40 -0300

tools lib: Move argv_{split,free} from tools/perf/util/

This came from the kernel lib/argv_split.c, so move it to
tools/lib/argv_split.c, to get it closer to the kernel structure.

We need to audit the usage of argv_split() to figure out if it is really
necessary to do have one allocation per argv[] entry, looking at one of
its users I guess that is not the case and we probably are even leaking
those allocations by not using argv_free() judiciously, for later.

With this we further remove stuff from tools/perf/util/, reducing the
perf specific codebase and encouraging other tools/ code to use these
routines so as to keep the style and constructs used with the kernel.

Cc: Adrian Hunter <adrian.hunter@xxxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
Cc: Namhyung Kim <namhyung@xxxxxxxxxx>
Link: https://lkml.kernel.org/n/tip-j479s1ive9h75w5lfg16jroz@xxxxxxxxxxxxxx
Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
---
tools/include/linux/string.h | 3 ++
tools/lib/argv_split.c | 100 +++++++++++++++++++++++++++++++++++++++++++
tools/perf/MANIFEST | 1 +
tools/perf/util/Build | 5 +++
tools/perf/util/string.c | 91 ---------------------------------------
tools/perf/util/string2.h | 2 -
6 files changed, 109 insertions(+), 93 deletions(-)

diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h
index a76d4df10435..980cb9266718 100644
--- a/tools/include/linux/string.h
+++ b/tools/include/linux/string.h
@@ -7,6 +7,9 @@

void *memdup(const void *src, size_t len);

+char **argv_split(const char *str, int *argcp);
+void argv_free(char **argv);
+
int strtobool(const char *s, bool *res);

/*
diff --git a/tools/lib/argv_split.c b/tools/lib/argv_split.c
new file mode 100644
index 000000000000..0a58ccf3f761
--- /dev/null
+++ b/tools/lib/argv_split.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Helper function for splitting a string into an argv-like array.
+ */
+
+#include <stdlib.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+static const char *skip_arg(const char *cp)
+{
+ while (*cp && !isspace(*cp))
+ cp++;
+
+ return cp;
+}
+
+static int count_argc(const char *str)
+{
+ int count = 0;
+
+ while (*str) {
+ str = skip_spaces(str);
+ if (*str) {
+ count++;
+ str = skip_arg(str);
+ }
+ }
+
+ return count;
+}
+
+/**
+ * argv_free - free an argv
+ * @argv - the argument vector to be freed
+ *
+ * Frees an argv and the strings it points to.
+ */
+void argv_free(char **argv)
+{
+ char **p;
+ for (p = argv; *p; p++) {
+ free(*p);
+ *p = NULL;
+ }
+
+ free(argv);
+}
+
+/**
+ * argv_split - split a string at whitespace, returning an argv
+ * @str: the string to be split
+ * @argcp: returned argument count
+ *
+ * Returns an array of pointers to strings which are split out from
+ * @str. This is performed by strictly splitting on white-space; no
+ * quote processing is performed. Multiple whitespace characters are
+ * considered to be a single argument separator. The returned array
+ * is always NULL-terminated. Returns NULL on memory allocation
+ * failure.
+ */
+char **argv_split(const char *str, int *argcp)
+{
+ int argc = count_argc(str);
+ char **argv = calloc(argc + 1, sizeof(*argv));
+ char **argvp;
+
+ if (argv == NULL)
+ goto out;
+
+ if (argcp)
+ *argcp = argc;
+
+ argvp = argv;
+
+ while (*str) {
+ str = skip_spaces(str);
+
+ if (*str) {
+ const char *p = str;
+ char *t;
+
+ str = skip_arg(str);
+
+ t = strndup(p, str-p);
+ if (t == NULL)
+ goto fail;
+ *argvp++ = t;
+ }
+ }
+ *argvp = NULL;
+
+out:
+ return argv;
+
+fail:
+ argv_free(argv);
+ return NULL;
+}
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index aac4c755d81b..6a5de44b2de9 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -7,6 +7,7 @@ tools/lib/traceevent
tools/lib/api
tools/lib/bpf
tools/lib/subcmd
+tools/lib/argv_split.c
tools/lib/ctype.c
tools/lib/hweight.c
tools/lib/rbtree.c
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index b4dc6112138f..d3408a463060 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -20,6 +20,7 @@ perf-y += parse-events.o
perf-y += perf_regs.o
perf-y += path.o
perf-y += print_binary.o
+perf-y += argv_split.o
perf-y += rbtree.o
perf-y += libstring.o
perf-y += bitmap.o
@@ -209,6 +210,10 @@ $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)

+$(OUTPUT)util/argv_split.o: ../lib/argv_split.c FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,cc_o_c)
+
$(OUTPUT)util/bitmap.o: ../lib/bitmap.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 9b7fbb0cbecd..52603876c548 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -69,97 +69,6 @@ out_err:
return -1;
}

-static const char *skip_arg(const char *cp)
-{
- while (*cp && !isspace(*cp))
- cp++;
-
- return cp;
-}
-
-static int count_argc(const char *str)
-{
- int count = 0;
-
- while (*str) {
- str = skip_spaces(str);
- if (*str) {
- count++;
- str = skip_arg(str);
- }
- }
-
- return count;
-}
-
-/**
- * argv_free - free an argv
- * @argv - the argument vector to be freed
- *
- * Frees an argv and the strings it points to.
- */
-void argv_free(char **argv)
-{
- char **p;
- for (p = argv; *p; p++) {
- free(*p);
- *p = NULL;
- }
-
- free(argv);
-}
-
-/**
- * argv_split - split a string at whitespace, returning an argv
- * @str: the string to be split
- * @argcp: returned argument count
- *
- * Returns an array of pointers to strings which are split out from
- * @str. This is performed by strictly splitting on white-space; no
- * quote processing is performed. Multiple whitespace characters are
- * considered to be a single argument separator. The returned array
- * is always NULL-terminated. Returns NULL on memory allocation
- * failure.
- */
-char **argv_split(const char *str, int *argcp)
-{
- int argc = count_argc(str);
- char **argv = calloc(argc + 1, sizeof(*argv));
- char **argvp;
-
- if (argv == NULL)
- goto out;
-
- if (argcp)
- *argcp = argc;
-
- argvp = argv;
-
- while (*str) {
- str = skip_spaces(str);
-
- if (*str) {
- const char *p = str;
- char *t;
-
- str = skip_arg(str);
-
- t = strndup(p, str-p);
- if (t == NULL)
- goto fail;
- *argvp++ = t;
- }
- }
- *argvp = NULL;
-
-out:
- return argv;
-
-fail:
- argv_free(argv);
- return NULL;
-}
-
/* Character class matching */
static bool __match_charclass(const char *pat, char c, const char **npat)
{
diff --git a/tools/perf/util/string2.h b/tools/perf/util/string2.h
index 2696c3fcd780..708805f5573e 100644
--- a/tools/perf/util/string2.h
+++ b/tools/perf/util/string2.h
@@ -11,8 +11,6 @@ extern const char *graph_dotted_line;
extern const char *dots;

s64 perf_atoll(const char *str);
-char **argv_split(const char *str, int *argcp);
-void argv_free(char **argv);
bool strglobmatch(const char *str, const char *pat);
bool strglobmatch_nocase(const char *str, const char *pat);
bool strlazymatch(const char *str, const char *pat);