From 4d453a8313c1eab29880666f3e34164c4e73d35c Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 2 Apr 2020 16:18:06 +0200
Subject: [PATCH] fs/NarrowPath: add class FromNarrowPath

Move code from ParseCommandLine().
---
 src/CommandLine.cxx   | 14 ++------------
 src/fs/NarrowPath.cxx | 19 +++++++++++++++++++
 src/fs/NarrowPath.hxx | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/src/CommandLine.cxx b/src/CommandLine.cxx
index 5ede49580..93396bc0b 100644
--- a/src/CommandLine.cxx
+++ b/src/CommandLine.cxx
@@ -33,11 +33,11 @@
 #include "playlist/PlaylistRegistry.hxx"
 #include "playlist/PlaylistPlugin.hxx"
 #include "fs/AllocatedPath.hxx"
+#include "fs/NarrowPath.hxx"
 #include "fs/Traits.hxx"
 #include "fs/FileSystem.hxx"
 #include "fs/StandardDirectory.hxx"
 #include "system/Error.hxx"
-#include "util/Macros.hxx"
 #include "util/RuntimeError.hxx"
 #include "util/Domain.hxx"
 #include "util/OptionDef.hxx"
@@ -380,17 +380,7 @@ ParseCommandLine(int argc, char **argv, struct options &options,
 
 	if (config_file != nullptr) {
 		/* use specified configuration file */
-#ifdef _UNICODE
-		wchar_t buffer[MAX_PATH];
-		auto result = MultiByteToWideChar(CP_ACP, 0, config_file, -1,
-						  buffer, ARRAY_SIZE(buffer));
-		if (result <= 0)
-			throw MakeLastError("MultiByteToWideChar() failed");
-
-		ReadConfigFile(config, Path::FromFS(buffer));
-#else
-		ReadConfigFile(config, Path::FromFS(config_file));
-#endif
+		ReadConfigFile(config, FromNarrowPath(config_file));
 		return;
 	}
 
diff --git a/src/fs/NarrowPath.cxx b/src/fs/NarrowPath.cxx
index 1939998ec..d92af7eae 100644
--- a/src/fs/NarrowPath.cxx
+++ b/src/fs/NarrowPath.cxx
@@ -22,6 +22,8 @@
 #ifdef _UNICODE
 
 #include "lib/icu/Win32.hxx"
+#include "system/Error.hxx"
+#include "util/Macros.hxx"
 
 #include <windows.h>
 
@@ -33,4 +35,21 @@ NarrowPath::NarrowPath(Path _path) noexcept
 		value = Value::Empty();
 }
 
+static AllocatedPath
+AcpToAllocatedPath(const char *s)
+{
+	wchar_t buffer[MAX_PATH];
+	auto result = MultiByteToWideChar(CP_ACP, 0, s, -1,
+					  buffer, ARRAY_SIZE(buffer));
+	if (result <= 0)
+		throw MakeLastError("MultiByteToWideChar() failed");
+
+	return AllocatedPath::FromFS(buffer);
+}
+
+FromNarrowPath::FromNarrowPath(const char *s)
+	:value(AcpToAllocatedPath(s))
+{
+}
+
 #endif /* _UNICODE */
diff --git a/src/fs/NarrowPath.hxx b/src/fs/NarrowPath.hxx
index df92053ba..48198ffbf 100644
--- a/src/fs/NarrowPath.hxx
+++ b/src/fs/NarrowPath.hxx
@@ -23,6 +23,7 @@
 #include "Path.hxx"
 
 #ifdef _UNICODE
+#include "AllocatedPath.hxx"
 #include "util/AllocatedString.hxx"
 #else
 #include "util/StringPointer.hxx"
@@ -59,4 +60,38 @@ public:
 	}
 };
 
+/**
+ * A path name converted from a "narrow" string.  This is used to
+ * import an existing narrow string to a #Path.
+ */
+class FromNarrowPath {
+#ifdef _UNICODE
+	using Value = AllocatedPath;
+#else
+	using Value = Path;
+#endif
+
+	Value value{nullptr};
+
+public:
+	FromNarrowPath() = default;
+
+#ifdef _UNICODE
+	/**
+	 * Throws on error.
+	 */
+	FromNarrowPath(const char *s);
+#else
+	constexpr FromNarrowPath(const char *s) noexcept
+		:value(Value::FromFS(s)) {}
+#endif
+
+#ifndef _UNICODE
+	constexpr
+#endif
+	operator Path() const noexcept {
+		return value;
+	}
+};
+
 #endif