From d1299360de4fe9816b73a56db89e053ac1754912 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= <fmang@mg0.fr>
Date: Sat, 24 Nov 2018 11:32:17 -0500
Subject: [PATCH] smart ot::file handle

---
 src/cli.cc     | 16 +++++++---------
 src/opustags.h | 13 +++++--------
 t/cli.cc       |  2 +-
 t/ogg.cc       | 20 ++++++++------------
 4 files changed, 21 insertions(+), 30 deletions(-)

diff --git a/src/cli.cc b/src/cli.cc
index ef62182..d83474a 100644
--- a/src/cli.cc
+++ b/src/cli.cc
@@ -293,29 +293,27 @@ ot::status ot::run(ot::options& opt)
 	if (!opt.path_out.empty() && same_file(opt.path_in, opt.path_out))
 		return {ot::st::fatal_error, "Input and output files are the same"};
 
-	std::unique_ptr<FILE, decltype(&fclose)> input(nullptr, &fclose);
+	ot::file input;
 	if (opt.path_in == "-") {
-		input.reset(stdin);
+		input = stdin;
 	} else {
-		FILE* input_file = fopen(opt.path_in.c_str(), "r");
-		if (input_file == nullptr)
+		input = fopen(opt.path_in.c_str(), "r");
+		if (input == nullptr)
 			return {ot::st::standard_error,
 			        "could not open '" + opt.path_in + "' for reading: " + strerror(errno)};
-		input.reset(input_file);
 	}
 
-	std::unique_ptr<FILE, decltype(&fclose)> output(nullptr, &fclose);
+	ot::file output;
 	if (opt.path_out == "-") {
 		output.reset(stdout);
 	} else if (!opt.path_out.empty()) {
 		if (!opt.overwrite && access(opt.path_out.c_str(), F_OK) == 0)
 			return {ot::st::fatal_error,
 			        "'" + opt.path_out + "' already exists (use -y to overwrite)"};
-		FILE* output_file = fopen(opt.path_out.c_str(), "w");
-		if (output_file == nullptr)
+		output = fopen(opt.path_out.c_str(), "w");
+		if (output == nullptr)
 			return {ot::st::standard_error,
 				"could not open '" + opt.path_out + "' for writing: " + strerror(errno)};
-		output.reset(output_file);
 	}
 
 	ot::status rc;
diff --git a/src/opustags.h b/src/opustags.h
index b91a836..53788b7 100644
--- a/src/opustags.h
+++ b/src/opustags.h
@@ -85,16 +85,13 @@ struct status {
 };
 
 /**
- * Call a fopen-like function that returns a FILE* such that the returned pointer is smart and calls
- * fclose on destruction.
+ * Smart auto-closing FILE* handle.
  *
- * Example : `auto my_file = ot::make_file(fopen, "foo.txt", "r");`
+ * It implictly converts from an already opened FILE*.
  */
-template <typename Opener, typename... Args>
-std::unique_ptr<FILE, decltype(&fclose)> make_file(Opener&& f, Args&&... args)
-{
-	return {f(std::forward<Args>(args)...), &fclose};
-}
+struct file : std::unique_ptr<FILE, decltype(&fclose)> {
+	file(FILE* f = nullptr) : std::unique_ptr<FILE, decltype(&fclose)>(f, &fclose) {}
+};
 
 /***********************************************************************************************//**
  * \defgroup ogg Ogg
diff --git a/t/cli.cc b/t/cli.cc
index 74bd4d4..2809260 100644
--- a/t/cli.cc
+++ b/t/cli.cc
@@ -10,7 +10,7 @@ Artist=Y
 
 void check_read_comments()
 {
-	auto input = ot::make_file(fmemopen, const_cast<char*>(user_comments), strlen(user_comments), "r");
+	ot::file input = fmemopen(const_cast<char*>(user_comments), strlen(user_comments), "r");
 	auto comments = ot::read_comments(input.get());
 	auto&& expected = {"TITLE=a b c", "ARTIST=X", "Artist=Y"};
 	if (!std::equal(comments.begin(), comments.end(), expected.begin(), expected.end()))
diff --git a/t/ogg.cc b/t/ogg.cc
index 21a4384..a55be2f 100644
--- a/t/ogg.cc
+++ b/t/ogg.cc
@@ -3,10 +3,9 @@
 
 static void check_ref_ogg()
 {
-	FILE* input_file = fopen("gobble.opus", "r");
-	if (input_file == nullptr)
+	ot::file input = fopen("gobble.opus", "r");
+	if (input == nullptr)
 		throw failure("could not open gobble.opus");
-	std::unique_ptr<FILE, decltype(&fclose)> input(input_file, &fclose);
 
 	ot::ogg_reader reader(input.get());
 
@@ -69,11 +68,10 @@ static void check_memory_ogg()
 	size_t my_ogg_size;
 	ot::status rc;
 
-	FILE* output_mem = fmemopen(my_ogg.data(), my_ogg.size(), "w");
-	if (output_mem == nullptr)
-		throw failure("could not open the output stream");
-	std::unique_ptr<FILE, decltype(&fclose)> output(output_mem, &fclose);
 	{
+		ot::file output = fmemopen(my_ogg.data(), my_ogg.size(), "w");
+		if (output == nullptr)
+			throw failure("could not open the output stream");
 		ot::ogg_writer writer(output.get());
 		rc = writer.prepare_stream(1234);
 		if (rc != ot::st::ok)
@@ -100,13 +98,11 @@ static void check_memory_ogg()
 		if (my_ogg_size != 73)
 			throw failure("unexpected output size");
 	}
-	output.reset();
 
-	FILE* input_mem = fmemopen(my_ogg.data(), my_ogg_size, "r");
-	if (input_mem == nullptr)
-		throw failure("could not open the input stream");
-	std::unique_ptr<FILE, decltype(&fclose)> input(input_mem, &fclose);
 	{
+		ot::file input = fmemopen(my_ogg.data(), my_ogg_size, "r");
+		if (input == nullptr)
+			throw failure("could not open the input stream");
 		ot::ogg_reader reader(input.get());
 		rc = reader.read_page();
 		if (rc != ot::st::ok)