From 0778d3c45d1aef18d9b2ae6769e372b2a3d83b8e Mon Sep 17 00:00:00 2001
From: Bent Bisballe Nyeng <deva@aasimon.org>
Date: Tue, 4 Mar 2025 09:41:00 +0100
Subject: New cross-platform argparser to replace getopt and getoptpp.

---
 src/configure.cc | 213 ++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 133 insertions(+), 80 deletions(-)

(limited to 'src/configure.cc')

diff --git a/src/configure.cc b/src/configure.cc
index a43152f..3d73011 100644
--- a/src/configure.cc
+++ b/src/configure.cc
@@ -8,8 +8,7 @@
 #include <fstream>
 #include <optional>
 #include <span>
-
-#include <getoptpp/getoptpp.hpp>
+#include <cstring>
 
 #include "execute.h"
 #include "ctor.h"
@@ -18,6 +17,7 @@
 #include "externals.h"
 #include "tools.h"
 #include "util.h"
+#include "argparser.h"
 
 const std::filesystem::path configurationFile("configuration.cc");
 const std::filesystem::path configHeaderFile("config.h");
@@ -236,8 +236,7 @@ int regenerateCache(ctor::settings& settings,
 {
 	Args vargs(args);
 
-	dg::Options opt;
-	int key{128};
+	arg::Parser<std::string> opt(static_cast<int>(vargs.size()), vargs.data());
 
 	std::string build_arch_prefix;
 	std::string build_path;
@@ -251,91 +250,103 @@ int regenerateCache(ctor::settings& settings,
 	std::string ctor_libdir;
 	std::string builddir;
 
-	opt.add("build-dir", required_argument, 'b',
-	        "Set output directory for build files (default: '" +
-	        settings.builddir + "').",
-	        [&]() {
-		        settings.builddir = optarg;
-		        builddir = optarg;
+	opt.add('b', "--build-dir",
+	        std::function([&](std::string arg)
+	        {
+		        settings.builddir = arg;
+		        builddir = arg;
 		        return 0;
-	        });
+	        }),
+	        "Set output directory for build files (default: '" +
+	        settings.builddir + "').");
 
-	opt.add("verbose", no_argument, 'v',
-	        "Be verbose. Add multiple times for more verbosity.",
-	        [&]() {
+	opt.add('v', "--verbose",
+	        std::function([&]()
+	        {
 		        settings.verbose++;
 		        return 0;
-	        });
+	        }),
+	        "Be verbose. Add multiple times for more verbosity.");
 
-	opt.add("cc", required_argument, key++,
-	        "Use specified c-compiler instead of gcc.",
-	        [&]() {
-		        cc_prog = optarg;
+	opt.add({}, "--cc",
+	        std::function([&](std::string arg)
+	        {
+		        cc_prog = arg;
 		        return 0;
-	        });
+	        }),
+	        "Use specified c-compiler instead of gcc.");
 
-	opt.add("cxx", required_argument, key++,
-	        "Use specified c++-compiler instead of g++.",
-	        [&]() {
-		        cxx_prog = optarg;
+	opt.add({}, "--cxx",
+	        std::function([&](std::string arg)
+	        {
+		        cxx_prog = arg;
 		        return 0;
-	        });
+	        }),
+	        "Use specified c++-compiler instead of g++.");
 
-	opt.add("ar", required_argument, key++,
-	        "Use specified archiver instead of ar.",
-	        [&]() {
-		        ar_prog = optarg;
+	opt.add({}, "--ar",
+	        std::function([&](std::string arg)
+	        {
+		        ar_prog = arg;
 		        return 0;
-	        });
+	        }),
+	        "Use specified archiver instead of ar.");
 
-	opt.add("ld", required_argument, key++,
-	        "Use specified linker instead of ld.",
-	        [&]() {
-		        ld_prog = optarg;
+	opt.add({}, "--ld",
+	        std::function([&](std::string arg)
+	        {
+		        ld_prog = arg;
 		        return 0;
-	        });
+	        }),
+	        "Use specified linker instead of ld.");
 
-	opt.add("build", required_argument, key++,
-	        "Configure for building on specified architecture.",
-	        [&]() {
-		        build_arch_prefix = optarg;
+	opt.add({}, "--build",
+	        std::function([&](std::string arg)
+	        {
+		        build_arch_prefix = arg;
 		        return 0;
-	        });
+	        }),
+	        "Configure for building on specified architecture.");
 
-	opt.add("build-path", required_argument, key++,
-	        "Set path to build tool-chain.",
-	        [&]() {
-		        build_path = optarg;
+	opt.add({}, "--build-path",
+	        std::function([&](std::string arg)
+	        {
+		        build_path = arg;
 		        return 0;
-	        });
+	        }),
+	        "Set path to build tool-chain.");
 
-	opt.add("host", required_argument, key++,
-	        "Cross-compile to build programs to run on specified architecture.",
-	        [&]() {
-		        host_arch_prefix = optarg;
+	opt.add({}, "--host",
+	        std::function([&](std::string arg)
+	        {
+		        host_arch_prefix = arg;
 		        return 0;
-	        });
+	        }),
+	        "Cross-compile to build programs to run on specified architecture.");
 
-	opt.add("host-path", required_argument, key++,
-	        "Set path to cross-compile tool-chain.",
-	        [&]() {
-		        host_path = optarg;
+	opt.add({}, "--host-path",
+	        std::function([&](std::string arg)
+	        {
+		        host_path = arg;
 		        return 0;
-	        });
+	        }),
+	        "Set path to cross-compile tool-chain.");
 
-	opt.add("ctor-includedir", required_argument, key++,
-	        "Set path to ctor header file, used for re-compiling.",
-	        [&]() {
-		        ctor_includedir = optarg;
+	opt.add({}, "--ctor-includedir",
+	        std::function([&](std::string arg)
+	        {
+		        ctor_includedir = arg;
 		        return 0;
-	        });
+	        }),
+	        "Set path to ctor header file, used for re-compiling.");
 
-	opt.add("ctor-libdir", required_argument, key++,
-	        "Set path to ctor library file, used for re-compiling.",
-	        [&]() {
-		        ctor_libdir = optarg;
+	opt.add({}, "--ctor-libdir",
+	        std::function([&](std::string arg)
+	        {
+		        ctor_libdir = arg;
 		        return 0;
-	        });
+	        }),
+	        "Set path to ctor library file, used for re-compiling.");
 
 	// Resolv externals
 	ctor::external_configurations externalConfigs;
@@ -350,19 +361,21 @@ int regenerateCache(ctor::settings& settings,
 	auto add_path_args =
 		[&](const std::string& arg_name)
 		{
-			opt.add(arg_name + "-includedir", required_argument, key++,
-			        "Set path to " + arg_name + " header file.",
-			        [&]() {
-				        external_includedir[arg_name] = optarg;
+			opt.add({}, "--" + arg_name + "-includedir",
+			        std::function([&](std::string arg)
+			        {
+				        external_includedir[arg_name] = arg;
 				        return 0;
-			        });
+			        }),
+			        "Set path to " + arg_name + " header file.");
 
-			opt.add(arg_name + "-libdir", required_argument, key++,
-			        "Set path to " + arg_name + " libraries.",
-			        [&]() {
-				        external_libdir[arg_name] = optarg;
+			opt.add({}, "--" + arg_name + "-libdir",
+			        std::function([&](std::string arg)
+			        {
+				        external_libdir[arg_name] = arg;
 				        return 0;
-			        });
+			        }),
+			        "Set path to " + arg_name + " libraries.");
 		};
 
 	for(const auto& ext : externalConfigs)
@@ -382,17 +395,57 @@ int regenerateCache(ctor::settings& settings,
 
 	}
 
-	opt.add("help", no_argument, 'h',
-	        "Print this help text.",
-	        [&]() -> int {
+	opt.add('h', "--help",
+	        std::function([&]() -> int
+	        {
 		        std::cout << "Configure how to build with " << name << "\n";
 		        std::cout << "Usage: " << name << " configure [options]\n\n";
 		        std::cout << "Options:\n";
 		        opt.help();
 		        exit(0);
-	        });
+	        }),
+	        "Print this help text.");
+
+	opt.set_err_cb(
+		[&](arg::error err, std::string_view arg)
+		{
+			switch(err)
+			{
+			case arg::error::invalid_arg:
+				std::cerr << opt.prog_name() <<
+					": invalid argument for option '" << arg << "'\n";
+				std::cerr << "Type '" << opt.prog_name() <<
+					" -h' for more information.\n";
+				break;
+
+			case arg::error::missing_arg:
+				std::cerr << opt.prog_name() << ": option requires and argument '" <<
+					arg << "'\n";
+				std::cerr << "Type '" << opt.prog_name() <<
+					" -h' for more information.\n";
+				break;
 
-	opt.process(static_cast<int>(vargs.size()), vargs.data());
+			case arg::error::invalid_opt:
+				std::cerr << opt.prog_name() << ": invalid option '" << arg << "'\n";
+				std::cerr << "Type '" << opt.prog_name() <<
+					" -h' for more information.\n";
+				break;
+			}
+		});
+
+	opt.set_pos_cb(
+		[&](std::string_view)
+		{
+			std::cerr <<
+				"The configure subcommand doesn't use positional arguments.\n";
+			return 1;
+		});
+
+	auto res = opt.parse();
+	if(res != 0)
+	{
+		return res;
+	}
 
 	if(host_arch_prefix.empty())
 	{
-- 
cgit v1.2.3