io/Path: new library replacing g_build_filename()
authorMax Kellermann <max@musicpd.org>
Mon, 3 Sep 2018 19:23:50 +0000 (21:23 +0200)
committerMax Kellermann <max@musicpd.org>
Mon, 3 Sep 2018 19:23:50 +0000 (21:23 +0200)
src/conf.cxx
src/io/Path.hxx [new file with mode: 0644]
src/plugin.cxx

index 825fe4b..e940e35 100644 (file)
@@ -25,6 +25,7 @@
 #include "colors.hxx"
 #include "screen_list.hxx"
 #include "options.hxx"
+#include "io/Path.hxx"
 #include "util/CharUtil.hxx"
 #include "util/ScopeExit.hxx"
 #include "util/StringStrip.hxx"
@@ -606,11 +607,9 @@ read_rc_file(char *filename)
 bool
 check_user_conf_dir()
 {
-       char *directory = g_build_filename(g_get_home_dir(), "." PACKAGE, nullptr);
-       AtScopeExit(directory) { g_free(directory); };
-
-       return g_file_test(directory, G_FILE_TEST_IS_DIR) ||
-               g_mkdir(directory, 0755) == 0;
+       const auto directory = BuildPath(g_get_home_dir(), "." PACKAGE);
+       return g_file_test(directory.c_str(), G_FILE_TEST_IS_DIR) ||
+               g_mkdir(directory.c_str(), 0755) == 0;
 }
 
 char *
diff --git a/src/io/Path.hxx b/src/io/Path.hxx
new file mode 100644 (file)
index 0000000..a6f9f29
--- /dev/null
@@ -0,0 +1,122 @@
+/* ncmpc (Ncurses MPD Client)
+ * (c) 2004-2018 The Music Player Daemon Project
+ * Project homepage: http://musicpd.org
+ *
+ * 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 2 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef IO_PATH_HXX
+#define IO_PATH_HXX
+
+#include "Compiler.h"
+
+#include <string>
+
+#include <string.h>
+
+namespace PathDetail {
+
+#ifdef _WIN32
+static constexpr char SEPARATOR = '\\';
+#else
+static constexpr char SEPARATOR = '/';
+#endif
+
+gcc_pure
+inline size_t
+GetLength(const char *s) noexcept
+{
+       return strlen(s);
+}
+
+gcc_pure
+inline size_t
+GetLength(const std::string &s) noexcept
+{
+       return s.length();
+}
+
+template<typename... Args>
+inline size_t
+FillLengths(size_t *lengths, Args&&... args) noexcept;
+
+template<typename First, typename... Args>
+inline size_t
+FillLengths(size_t *lengths, First &&first, Args&&... args) noexcept
+{
+       size_t length = GetLength(std::forward<First>(first));
+       *lengths++ = length;
+       return length + FillLengths(lengths, std::forward<Args>(args)...);
+}
+
+template<>
+inline size_t
+FillLengths(size_t *) noexcept
+{
+       return 0;
+}
+
+inline std::string &
+Append(std::string &dest, const std::string &value, size_t length) noexcept
+{
+       return dest.append(value, 0, length);
+}
+
+inline std::string &
+Append(std::string &dest, const char *value, size_t length) noexcept
+{
+       return dest.append(value, length);
+}
+
+template<typename First, typename... Args>
+inline std::string &
+AppendWithSeparators(std::string &dest, const size_t *lengths,
+                    First &&first, Args&&... args) noexcept
+{
+       return AppendWithSeparators(AppendWithSeparators(dest, lengths,
+                                                        std::forward<First>(first)),
+                                   lengths + 1,
+                                   std::forward<Args>(args)...);
+}
+
+template<typename First>
+inline std::string &
+AppendWithSeparators(std::string &dest, const size_t *lengths,
+                    First &&first) noexcept
+{
+       dest.push_back(SEPARATOR);
+       return Append(dest, std::forward<First>(first), *lengths);
+}
+
+} // namespace PathDetail
+
+template<typename First, typename... Args>
+std::string
+BuildPath(First &&first, Args&&... args) noexcept
+{
+       constexpr size_t n = sizeof...(args);
+
+       size_t lengths[n + 1];
+       const size_t total = PathDetail::FillLengths(lengths, first, args...);
+
+       std::string result;
+       result.reserve(total + n);
+       PathDetail::Append(result, std::forward<First>(first), lengths[0]);
+       PathDetail::AppendWithSeparators(result, lengths + 1,
+                                        std::forward<Args>(args)...);
+       return result;
+}
+
+#endif
index b92db3c..42632dd 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include "plugin.hxx"
+#include "io/Path.hxx"
 #include "Compiler.h"
 
 #include <glib.h>
@@ -102,13 +103,13 @@ struct PluginCycle {
 };
 
 static bool
-register_plugin(PluginList *list, char *path)
+register_plugin(PluginList *list, std::string &&path)
 {
        struct stat st;
-       if (stat(path, &st) < 0)
+       if (stat(path.c_str(), &st) < 0)
                return false;
 
-       list->plugins.emplace_back(path);
+       list->plugins.emplace_back(std::move(path));
        return true;
 }
 
@@ -121,9 +122,7 @@ plugin_list_load_directory(PluginList *list, const char *path)
 
        const char *name;
        while ((name = g_dir_read_name(dir)) != nullptr) {
-               char *plugin = g_build_filename(path, name, nullptr);
-               register_plugin(list, plugin);
-               g_free(plugin);
+               register_plugin(list, BuildPath(path, name));
        }
 
        g_dir_close(dir);