commit:     6fd30de56d2db6dc6147a48155299b363cb8db8c
Author:     Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Sat Nov 22 19:58:45 2025 +0000
Commit:     Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Sat Nov 22 20:02:11 2025 +0000
URL:        https://gitweb.gentoo.org/proj/steve.git/commit/?id=6fd30de5

Rewrite argument parsing using getopt_long()

Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>

 meson.build |   6 ++-
 steve.cxx   | 128 ++++++++++++++++++++++++++++++------------------------------
 2 files changed, 68 insertions(+), 66 deletions(-)

diff --git a/meson.build b/meson.build
index 693c753..d5dad75 100644
--- a/meson.build
+++ b/meson.build
@@ -1,8 +1,12 @@
-project('steve', 'cpp')
+project('steve', 'cpp',
+        version : '0')
+
+version = meson.project_version()
 
 fuse3 = dependency('fuse3')
 libevent = dependency('libevent', version: '>= 2')
 
 executable('steve', ['steve.cxx'],
+           cpp_args : [f'-DSTEVE_VERSION="@version@"'],
            dependencies: [fuse3, libevent],
            install : true)

diff --git a/steve.cxx b/steve.cxx
index b00072e..d666f5c 100644
--- a/steve.cxx
+++ b/steve.cxx
@@ -14,6 +14,7 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cerrno>
+#include <climits>
 #include <csignal>
 #include <deque>
 #include <functional>
@@ -21,6 +22,7 @@
 #include <string>
 #include <unordered_map>
 
+#include <getopt.h>
 #include <sys/poll.h>
 #include <sys/syscall.h>
 #include <unistd.h>
@@ -31,16 +33,6 @@
 #include <fuse.h>
 #include <fuse_opt.h>
 
-static const char *usage =
-"usage: steve [options]\n"
-"\n"
-"options:\n"
-"    --help|-h             print this help message\n"
-"    --jobs=JOBS|-j JOBS   jobs to use (default: nproc)\n"
-"    --verbose|-v          enable verbose logging\n"
-"    -d   -o debug         enable debug output (implies -f)\n"
-"\n";
-
 struct steve_read_waiter {
        fuse_req_t req;
        uint64_t pid;
@@ -82,45 +74,6 @@ struct steve_state {
        struct event_base *evb;
 };
 
-enum steve_arg_keys {
-       STEVE_HELP,
-       STEVE_VERBOSE,
-};
-
-#define STEVE_OPT(t, p) { t, offsetof(steve_state, p), 1 }
-
-static const struct fuse_opt steve_opts[] = {
-       STEVE_OPT("-j %u", jobs),
-       STEVE_OPT("--jobs=%u", jobs),
-       FUSE_OPT_KEY("-v", STEVE_VERBOSE),
-       FUSE_OPT_KEY("--verbose", STEVE_VERBOSE),
-       FUSE_OPT_KEY("-h", STEVE_HELP),
-       FUSE_OPT_KEY("--help", STEVE_HELP),
-       FUSE_OPT_END
-};
-
-static int steve_process_arg(
-       void *userdata, const char *arg, int key, struct fuse_args *outargs)
-{
-       steve_state *state = static_cast<steve_state *>(userdata);
-
-       (void) outargs;
-       (void) arg;
-
-       switch (key) {
-       case STEVE_HELP:
-               fprintf(stderr, "%s", usage);
-               return fuse_opt_add_arg(outargs, "-ho");
-       case STEVE_VERBOSE:
-               state->verbose = true;
-               break;
-       default:
-               return 1;
-       }
-
-       return 0;
-}
-
 static void steve_wake_waiters(steve_state *state)
 {
        while (state->tokens > 0 && !state->read_waiters.empty()) {
@@ -360,10 +313,63 @@ static void steve_handle_cuse(evutil_socket_t, short, 
void *userdata) {
                fuse_session_process_buf(session, &buf);
 }
 
+static const char *steve_usage =
+"usage: %s [options]\n"
+"\n"
+"options:\n"
+"    --help, -h             print this help message\n"
+"    --version, -V          print version\n"
+"    --jobs=JOBS, -j JOBS   jobs to use (default: nproc)\n"
+"    --verbose, -v          enable verbose logging\n"
+"    --debug, -d            enable FUSE debug output\n";
+
+static const struct option steve_opts[] = {
+       { "help", no_argument, 0, 'h' },
+       { "version", no_argument, 0, 'V' },
+       { "jobs", required_argument, 0, 'j' },
+       { "verbose", no_argument, 0, 'v' },
+       { "debug", no_argument, 0, 'd' },
+       { 0 },
+};
+
 int main(int argc, char **argv)
 {
        steve_state state = { 0 };
 
+       int opt;
+       bool debug = false;
+       while ((opt = getopt_long(argc, argv, "hVj:vd", steve_opts, nullptr)) 
!= -1) {
+               switch (opt) {
+                       case 'h':
+                               printf(steve_usage, argv[0]);
+                               return 0;
+                       case 'V':
+                               printf("steve %s\n", STEVE_VERSION);
+                               return 0;
+                       case 'j':
+                               {
+                                       char *endptr;
+                                       errno = 0;
+                                       long jobs_arg = strtol(optarg, &endptr, 
10);
+                                       if (*endptr || errno == ERANGE || 
jobs_arg < 0 || jobs_arg > INT_MAX) {
+                                               fprintf(stderr, "invalid job 
number: %s\n", optarg);
+                                               return 1;
+                                       }
+                                       state.jobs = jobs_arg;
+                               }
+                               break;
+                       case 'v':
+                               state.verbose = true;
+                               break;
+                       case 'd':
+                               debug = true;
+                               break;
+                       default:
+                               fprintf(stderr, steve_usage, argv[0]);
+                               return 1;
+               }
+       }
+
        std::unique_ptr<struct event_base, std::function<void(struct 
event_base*)>>
                evb{event_base_new(), event_base_free};
        if (!evb) {
@@ -372,17 +378,9 @@ int main(int argc, char **argv)
        }
        state.evb = evb.get();
 
-       struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
-       if (fuse_opt_parse(&args, &state, steve_opts, steve_process_arg)) {
-               fprintf(stderr, "failed to parse option\n");
-               fuse_opt_free_args(&args);
-               return 1;
-       }
-
        int cuse_fd = open("/dev/cuse", O_RDWR);
        if (cuse_fd == -1) {
                perror("unable to open /dev/cuse");
-               fuse_opt_free_args(&args);
                return 1;
        }
 
@@ -394,12 +392,18 @@ int main(int argc, char **argv)
        if (state.jobs == 0)
                state.jobs = sysconf(_SC_NPROCESSORS_ONLN);
 
+       struct fuse_args args = FUSE_ARGS_INIT(0, nullptr);
+       std::unique_ptr<struct fuse_args, std::function<void(struct 
fuse_args*)>>
+               args_ptr{&args, fuse_opt_free_args};
+       fuse_opt_add_arg(args_ptr.get(), argv[0]);
+       if (debug)
+               fuse_opt_add_arg(args_ptr.get(), "-d");
+
        std::unique_ptr<struct fuse_session, std::function<void(struct 
fuse_session*)>> session{
-               cuse_lowlevel_new(&args, &ci, &steve_ops, &state), 
fuse_session_destroy};
+               cuse_lowlevel_new(args_ptr.get(), &ci, &steve_ops, &state), 
fuse_session_destroy};
        if (!session) {
                fprintf(stderr, "failed to initialize FUSE");
                close(cuse_fd);
-               fuse_opt_free_args(&args);
                return 1;
        }
 
@@ -408,13 +412,11 @@ int main(int argc, char **argv)
        if (!cuse_event) {
                fprintf(stderr, "failed to initialize CUSE handler");
                close(cuse_fd);
-               fuse_opt_free_args(&args);
                return 1;
        }
        if (event_add(cuse_event.get(), nullptr) == -1) {
                fprintf(stderr, "failed to enable CUSE handler");
                close(cuse_fd);
-               fuse_opt_free_args(&args);
                return 1;
        }
 
@@ -423,13 +425,11 @@ int main(int argc, char **argv)
        if (!sigusr1_event) {
                fprintf(stderr, "failed to initialize SIGUSR1 handler");
                close(cuse_fd);
-               fuse_opt_free_args(&args);
                return 1;
        }
        if (event_add(sigusr1_event.get(), nullptr) == -1) {
                fprintf(stderr, "failed to enable SIGUSR1 handler");
                close(cuse_fd);
-               fuse_opt_free_args(&args);
                return 1;
        }
 
@@ -437,13 +437,11 @@ int main(int argc, char **argv)
        if (fuse_session_mount(session.get(), mountpoint.c_str()) == -1) {
                fprintf(stderr, "failed to mount the filesystem");
                close(cuse_fd);
-               fuse_opt_free_args(&args);
                return 1;
        }
 
        event_base_dispatch(evb.get());
        fuse_session_unmount(session.get());
        close(cuse_fd);
-       fuse_opt_free_args(&args);
        return 0;
 }

Reply via email to