common: compile libstring-utils as C++
authorSimon Marchi <simon.marchi@efficios.com>
Fri, 3 Sep 2021 21:31:29 +0000 (17:31 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 17 Nov 2021 23:39:09 +0000 (18:39 -0500)
The code of string-utils.cpp is compiled as C++, but the functions are
still exported as C symbols for the moment (until all users are
converted to C++).

The only thing of interest here is this error:

      CXX      string-utils.lo
    /home/simark/src/lttng-tools/src/common/string-utils/string-utils.cpp: In function ‘star_glob_pattern_type_flags strutils_test_glob_pattern(const char*)’:
    /home/simark/src/lttng-tools/src/common/string-utils/string-utils.cpp:89:37: error: invalid conversion from ‘int’ to ‘star_glob_pattern_type_flags’ [-fpermissive]
       89 |                                 ret |= STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY;
          |                                 ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          |                                     |
          |                                     int

In C++, you can't freely use bitwise operator on enumerators.  I added
an operator|= free function to handle it, which converts to the
underlying type and back.  If we have many of these enums used as flags,
we could think of adding a class for that, like enum_flags in GDB:

https://gitlab.com/gnutools/binutils-gdb/-/blob/7a6cb96b710257a4f5bc7e85cc103b6bf8dfc25c/gdbsupport/enum-flags.h

Change-Id: I64b458a6f6c1e5a131525826a116607eef824aaa
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/common/string-utils/Makefile.am
src/common/string-utils/string-utils.c [deleted file]
src/common/string-utils/string-utils.cpp [new file with mode: 0644]

index 973c1d1e7281175c7ac2b878a0a381cdc3b0ba62..212b3d567c4aef8315c5d2ce10154564e5c41713 100644 (file)
@@ -2,4 +2,7 @@
 
 noinst_LTLIBRARIES = libstring-utils.la
 
-libstring_utils_la_SOURCES = string-utils.h string-utils.c format.h
+libstring_utils_la_SOURCES = \
+       format.h \
+       string-utils.cpp \
+       string-utils.h
diff --git a/src/common/string-utils/string-utils.c b/src/common/string-utils/string-utils.c
deleted file mode 100644 (file)
index 1bf0cc0..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-
-#include "string-utils.h"
-#include "../macros.h"
-
-enum star_glob_pattern_type_flags {
-       STAR_GLOB_PATTERN_TYPE_FLAG_NONE = 0,
-       STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN = 1,
-       STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY = 2,
-};
-
-/*
- * Normalizes the star-only globbing pattern `pattern`, that is, crushes
- * consecutive `*` characters into a single `*`, avoiding `\*`.
- */
-void strutils_normalize_star_glob_pattern(char *pattern)
-{
-       const char *p;
-       char *np;
-       bool got_star = false;
-
-       LTTNG_ASSERT(pattern);
-
-       for (p = pattern, np = pattern; *p != '\0'; p++) {
-               switch (*p) {
-               case '*':
-                       if (got_star) {
-                               /* Avoid consecutive stars. */
-                               continue;
-                       }
-
-                       got_star = true;
-                       break;
-               case '\\':
-                       /* Copy backslash character. */
-                       *np = *p;
-                       np++;
-                       p++;
-
-                       if (*p == '\0') {
-                               goto end;
-                       }
-
-                       /* Fall through default case. */
-               default:
-                       got_star = false;
-                       break;
-               }
-
-               /* Copy single character. */
-               *np = *p;
-               np++;
-       }
-
-end:
-       *np = '\0';
-}
-
-static
-enum star_glob_pattern_type_flags strutils_test_glob_pattern(const char *pattern)
-{
-       enum star_glob_pattern_type_flags ret =
-               STAR_GLOB_PATTERN_TYPE_FLAG_NONE;
-       const char *p;
-
-       LTTNG_ASSERT(pattern);
-
-       for (p = pattern; *p != '\0'; p++) {
-               switch (*p) {
-               case '*':
-                       ret = STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN;
-
-                       if (p[1] == '\0') {
-                               ret |= STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY;
-                       }
-
-                       goto end;
-               case '\\':
-                       p++;
-
-                       if (*p == '\0') {
-                               goto end;
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Returns true if `pattern` is a star-only globbing pattern, that is,
- * it contains at least one non-escaped `*`.
- */
-bool strutils_is_star_glob_pattern(const char *pattern)
-{
-       return strutils_test_glob_pattern(pattern) &
-               STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN;
-}
-
-/*
- * Returns true if `pattern` is a globbing pattern with a globbing,
- * non-escaped star only at its very end.
- */
-bool strutils_is_star_at_the_end_only_glob_pattern(const char *pattern)
-{
-       return strutils_test_glob_pattern(pattern) &
-               STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY;
-}
-
-/*
- * Unescapes the input string `input`, that is, in a `\x` sequence,
- * removes `\`. If `only_char` is not 0, only this character is
- * escaped.
- */
-char *strutils_unescape_string(const char *input, char only_char)
-{
-       char *output;
-       char *o;
-       const char *i;
-
-       LTTNG_ASSERT(input);
-       output = zmalloc(strlen(input) + 1);
-       if (!output) {
-               goto end;
-       }
-
-       for (i = input, o = output; *i != '\0'; i++) {
-               switch (*i) {
-               case '\\':
-                       if (only_char && i[1] != only_char) {
-                               break;
-                       }
-
-                       i++;
-
-                       if (*i == '\0') {
-                               /* Copy last `\`. */
-                               *o = '\\';
-                               o++;
-                               goto end;
-                       }
-               default:
-                       break;
-               }
-
-               /* Copy single character. */
-               *o = *i;
-               o++;
-       }
-
-end:
-       return output;
-}
-
-/*
- * Frees a null-terminated array of strings, including each contained
- * string.
- */
-void strutils_free_null_terminated_array_of_strings(char **array)
-{
-       char **item;
-
-       if (!array) {
-               return;
-       }
-
-       for (item = array; *item; item++) {
-               free(*item);
-       }
-
-       free(array);
-}
-
-/*
- * Splits the input string `input` using the given delimiter `delim`.
- *
- * The return value is a dynamic pointer array that is assumed to be empty. The
- * array must be discarded by the caller by invoking
- * lttng_dynamic_pointer_array_reset().
- *
- * Empty substrings are part of the result. For example:
- *
- *     Input: ,hello,,there,
- *     Result:
- *       ``
- *       `hello`
- *       ``
- *       `there`
- *       ``
- *
- * If `escape_delim` is true, then `\,`, where `,` is the delimiter,
- * escapes the delimiter and is copied as `,` only in the resulting
- * substring. For example:
- *
- *     Input: hello\,world,zoom,\,hi
- *     Result:
- *       `hello,world`
- *       `zoom`
- *       `,hi`
- *
- * Other characters are not escaped (this is the caller's job if
- * needed). However they are considering during the parsing, that is,
- * `\x`, where `x` is any character, is copied as is to the resulting
- * substring, e.g.:
- *
- *     Input: hello\,wo\rld\\,zoom\,
- *     Result:
- *       `hello,wo\rld\\`
- *       `zoom,`
- *
- * If `escape_delim` is false, nothing at all is escaped, and `delim`,
- * when found in `input`, is always a delimiter, e.g.:
- *
- *     Input: hello\,world,zoom,\,hi
- *     Result:
- *       `hello\`
- *       `world`
- *       `zoom`
- *       `\`
- *       `hi`
- *
- * Returns -1 if there's an error.
- */
-int strutils_split(const char *input,
-               char delim,
-               bool escape_delim,
-               struct lttng_dynamic_pointer_array *out_strings)
-{
-       int ret;
-       size_t at;
-       size_t number_of_substrings = 1;
-       size_t longest_substring_len = 0;
-       const char *s;
-       const char *last;
-
-       LTTNG_ASSERT(input);
-       LTTNG_ASSERT(!(escape_delim && delim == '\\'));
-       LTTNG_ASSERT(delim != '\0');
-       lttng_dynamic_pointer_array_init(out_strings, free);
-
-       /* First pass: count the number of substrings. */
-       for (s = input, last = input - 1; *s != '\0'; s++) {
-               if (escape_delim && *s == '\\') {
-                       /* Ignore following (escaped) character. */
-                       s++;
-
-                       if (*s == '\0') {
-                               break;
-                       }
-
-                       continue;
-               }
-
-               if (*s == delim) {
-                       size_t last_len = s - last - 1;
-                       last = s;
-                       number_of_substrings++;
-
-                       if (last_len > longest_substring_len) {
-                               longest_substring_len = last_len;
-                       }
-               }
-       }
-
-       if ((s - last - 1) > longest_substring_len) {
-               longest_substring_len = s - last - 1;
-       }
-
-       /* Second pass: actually split and copy substrings. */
-       for (at = 0, s = input; at < number_of_substrings; at++) {
-               const char *ss;
-               char *d;
-               char *substring = zmalloc(longest_substring_len + 1);
-
-               if (!substring) {
-                       goto error;
-               }
-
-               ret = lttng_dynamic_pointer_array_add_pointer(
-                               out_strings, substring);
-               if (ret) {
-                       free(substring);
-                       goto error;
-               }
-
-               /*
-                * Copy characters to substring until we find the next
-                * delimiter or the end of the input string.
-                */
-               for (ss = s, d = substring; *ss != '\0'; ss++) {
-                       if (escape_delim && *ss == '\\') {
-                               if (ss[1] == delim) {
-                                       /*
-                                        * '\' followed by delimiter and
-                                        * we need to escape this ('\'
-                                        * won't be part of the
-                                        * resulting substring).
-                                        */
-                                       ss++;
-                                       *d = *ss;
-                                       d++;
-                                       continue;
-                               } else {
-                                       /*
-                                        * Copy '\' and the following
-                                        * character.
-                                        */
-                                       *d = *ss;
-                                       d++;
-                                       ss++;
-
-                                       if (*ss == '\0') {
-                                               break;
-                                       }
-                               }
-                       } else if (*ss == delim) {
-                               /* We're done with this substring. */
-                               break;
-                       }
-
-                       *d = *ss;
-                       d++;
-               }
-
-               /* Next substring starts after the last delimiter. */
-               s = ss + 1;
-       }
-
-       ret = 0;
-       goto end;
-
-error:
-       ret = -1;
-end:
-       return ret;
-}
-
-size_t strutils_array_of_strings_len(char * const *array)
-{
-       char * const *item;
-       size_t count = 0;
-
-       LTTNG_ASSERT(array);
-
-       for (item = array; *item; item++) {
-               count++;
-       }
-
-       return count;
-}
diff --git a/src/common/string-utils/string-utils.cpp b/src/common/string-utils/string-utils.cpp
new file mode 100644 (file)
index 0000000..3051644
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <type_traits>
+
+#include "string-utils.h"
+#include "../macros.h"
+
+enum star_glob_pattern_type_flags {
+       STAR_GLOB_PATTERN_TYPE_FLAG_NONE = 0,
+       STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN = 1,
+       STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY = 2,
+};
+
+static
+star_glob_pattern_type_flags &operator|=(star_glob_pattern_type_flags &l,
+               star_glob_pattern_type_flags r)
+{
+       using T = std::underlying_type<star_glob_pattern_type_flags>::type;
+       l = static_cast<star_glob_pattern_type_flags> (
+               static_cast<T> (l) | static_cast<T> (r));
+       return l;
+}
+
+/*
+ * Normalizes the star-only globbing pattern `pattern`, that is, crushes
+ * consecutive `*` characters into a single `*`, avoiding `\*`.
+ */
+void strutils_normalize_star_glob_pattern(char *pattern)
+{
+       const char *p;
+       char *np;
+       bool got_star = false;
+
+       LTTNG_ASSERT(pattern);
+
+       for (p = pattern, np = pattern; *p != '\0'; p++) {
+               switch (*p) {
+               case '*':
+                       if (got_star) {
+                               /* Avoid consecutive stars. */
+                               continue;
+                       }
+
+                       got_star = true;
+                       break;
+               case '\\':
+                       /* Copy backslash character. */
+                       *np = *p;
+                       np++;
+                       p++;
+
+                       if (*p == '\0') {
+                               goto end;
+                       }
+
+                       /* Fall through default case. */
+               default:
+                       got_star = false;
+                       break;
+               }
+
+               /* Copy single character. */
+               *np = *p;
+               np++;
+       }
+
+end:
+       *np = '\0';
+}
+
+static
+enum star_glob_pattern_type_flags strutils_test_glob_pattern(const char *pattern)
+{
+       enum star_glob_pattern_type_flags ret =
+               STAR_GLOB_PATTERN_TYPE_FLAG_NONE;
+       const char *p;
+
+       LTTNG_ASSERT(pattern);
+
+       for (p = pattern; *p != '\0'; p++) {
+               switch (*p) {
+               case '*':
+                       ret = STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN;
+
+                       if (p[1] == '\0') {
+                               ret |= STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY;
+                       }
+
+                       goto end;
+               case '\\':
+                       p++;
+
+                       if (*p == '\0') {
+                               goto end;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Returns true if `pattern` is a star-only globbing pattern, that is,
+ * it contains at least one non-escaped `*`.
+ */
+bool strutils_is_star_glob_pattern(const char *pattern)
+{
+       return strutils_test_glob_pattern(pattern) &
+               STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN;
+}
+
+/*
+ * Returns true if `pattern` is a globbing pattern with a globbing,
+ * non-escaped star only at its very end.
+ */
+bool strutils_is_star_at_the_end_only_glob_pattern(const char *pattern)
+{
+       return strutils_test_glob_pattern(pattern) &
+               STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY;
+}
+
+/*
+ * Unescapes the input string `input`, that is, in a `\x` sequence,
+ * removes `\`. If `only_char` is not 0, only this character is
+ * escaped.
+ */
+char *strutils_unescape_string(const char *input, char only_char)
+{
+       char *output;
+       char *o;
+       const char *i;
+
+       LTTNG_ASSERT(input);
+       output = (char *) zmalloc(strlen(input) + 1);
+       if (!output) {
+               goto end;
+       }
+
+       for (i = input, o = output; *i != '\0'; i++) {
+               switch (*i) {
+               case '\\':
+                       if (only_char && i[1] != only_char) {
+                               break;
+                       }
+
+                       i++;
+
+                       if (*i == '\0') {
+                               /* Copy last `\`. */
+                               *o = '\\';
+                               o++;
+                               goto end;
+                       }
+               default:
+                       break;
+               }
+
+               /* Copy single character. */
+               *o = *i;
+               o++;
+       }
+
+end:
+       return output;
+}
+
+/*
+ * Frees a null-terminated array of strings, including each contained
+ * string.
+ */
+void strutils_free_null_terminated_array_of_strings(char **array)
+{
+       char **item;
+
+       if (!array) {
+               return;
+       }
+
+       for (item = array; *item; item++) {
+               free(*item);
+       }
+
+       free(array);
+}
+
+/*
+ * Splits the input string `input` using the given delimiter `delim`.
+ *
+ * The return value is a dynamic pointer array that is assumed to be empty. The
+ * array must be discarded by the caller by invoking
+ * lttng_dynamic_pointer_array_reset().
+ *
+ * Empty substrings are part of the result. For example:
+ *
+ *     Input: ,hello,,there,
+ *     Result:
+ *       ``
+ *       `hello`
+ *       ``
+ *       `there`
+ *       ``
+ *
+ * If `escape_delim` is true, then `\,`, where `,` is the delimiter,
+ * escapes the delimiter and is copied as `,` only in the resulting
+ * substring. For example:
+ *
+ *     Input: hello\,world,zoom,\,hi
+ *     Result:
+ *       `hello,world`
+ *       `zoom`
+ *       `,hi`
+ *
+ * Other characters are not escaped (this is the caller's job if
+ * needed). However they are considering during the parsing, that is,
+ * `\x`, where `x` is any character, is copied as is to the resulting
+ * substring, e.g.:
+ *
+ *     Input: hello\,wo\rld\\,zoom\,
+ *     Result:
+ *       `hello,wo\rld\\`
+ *       `zoom,`
+ *
+ * If `escape_delim` is false, nothing at all is escaped, and `delim`,
+ * when found in `input`, is always a delimiter, e.g.:
+ *
+ *     Input: hello\,world,zoom,\,hi
+ *     Result:
+ *       `hello\`
+ *       `world`
+ *       `zoom`
+ *       `\`
+ *       `hi`
+ *
+ * Returns -1 if there's an error.
+ */
+int strutils_split(const char *input,
+               char delim,
+               bool escape_delim,
+               struct lttng_dynamic_pointer_array *out_strings)
+{
+       int ret;
+       size_t at;
+       size_t number_of_substrings = 1;
+       size_t longest_substring_len = 0;
+       const char *s;
+       const char *last;
+
+       LTTNG_ASSERT(input);
+       LTTNG_ASSERT(!(escape_delim && delim == '\\'));
+       LTTNG_ASSERT(delim != '\0');
+       lttng_dynamic_pointer_array_init(out_strings, free);
+
+       /* First pass: count the number of substrings. */
+       for (s = input, last = input - 1; *s != '\0'; s++) {
+               if (escape_delim && *s == '\\') {
+                       /* Ignore following (escaped) character. */
+                       s++;
+
+                       if (*s == '\0') {
+                               break;
+                       }
+
+                       continue;
+               }
+
+               if (*s == delim) {
+                       size_t last_len = s - last - 1;
+                       last = s;
+                       number_of_substrings++;
+
+                       if (last_len > longest_substring_len) {
+                               longest_substring_len = last_len;
+                       }
+               }
+       }
+
+       if ((s - last - 1) > longest_substring_len) {
+               longest_substring_len = s - last - 1;
+       }
+
+       /* Second pass: actually split and copy substrings. */
+       for (at = 0, s = input; at < number_of_substrings; at++) {
+               const char *ss;
+               char *d;
+               char *substring = (char *) zmalloc(longest_substring_len + 1);
+
+               if (!substring) {
+                       goto error;
+               }
+
+               ret = lttng_dynamic_pointer_array_add_pointer(
+                               out_strings, substring);
+               if (ret) {
+                       free(substring);
+                       goto error;
+               }
+
+               /*
+                * Copy characters to substring until we find the next
+                * delimiter or the end of the input string.
+                */
+               for (ss = s, d = substring; *ss != '\0'; ss++) {
+                       if (escape_delim && *ss == '\\') {
+                               if (ss[1] == delim) {
+                                       /*
+                                        * '\' followed by delimiter and
+                                        * we need to escape this ('\'
+                                        * won't be part of the
+                                        * resulting substring).
+                                        */
+                                       ss++;
+                                       *d = *ss;
+                                       d++;
+                                       continue;
+                               } else {
+                                       /*
+                                        * Copy '\' and the following
+                                        * character.
+                                        */
+                                       *d = *ss;
+                                       d++;
+                                       ss++;
+
+                                       if (*ss == '\0') {
+                                               break;
+                                       }
+                               }
+                       } else if (*ss == delim) {
+                               /* We're done with this substring. */
+                               break;
+                       }
+
+                       *d = *ss;
+                       d++;
+               }
+
+               /* Next substring starts after the last delimiter. */
+               s = ss + 1;
+       }
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = -1;
+end:
+       return ret;
+}
+
+size_t strutils_array_of_strings_len(char * const *array)
+{
+       char * const *item;
+       size_t count = 0;
+
+       LTTNG_ASSERT(array);
+
+       for (item = array; *item; item++) {
+               count++;
+       }
+
+       return count;
+}
This page took 0.042622 seconds and 4 git commands to generate.