Skip to content

Replace getopt_long with popl.hpp for CLI option parsing#302

Open
iareARiES wants to merge 6 commits intoHSF:mainfrom
iareARiES:aditya-contribution
Open

Replace getopt_long with popl.hpp for CLI option parsing#302
iareARiES wants to merge 6 commits intoHSF:mainfrom
iareARiES:aditya-contribution

Conversation

@iareARiES
Copy link

@iareARiES iareARiES commented Feb 19, 2026

Addresses #243

The existing argument parsing in main() used getopt_long, which required maintaining three separate places in sync for every option — the static struct option array, the switch-case block, and the manual if (do_help) help text. Adding or changing any option meant updating all three. The help text was entirely hand-written, so it could silently go out of sync with the actual options.

What I changed

Only package/src/prmon.cpp was modified:

  • Swapped #include <getopt.h> for #include "popl.hpp"
  • Removed the long_options[] array, the getopt_long while loop, and the ~60 line manual help block
  • Replaced them with a popl::OptionParser registering all 12 options in one place
  • The -- separator scan is preserved — argv is scanned for -- before op.parse() so child program arguments are never consumed by popl
  • Repeatable options (--netdev, --disable, --level) are handled via count()/value(idx) loops
  • All post-parse logic (env variable handling, logger setup, pid/child dispatch) is unchanged

popl.hpp was vendored as a single header at package/include/popl.hpp — no new external dependency.

Behavior

No functional changes intended. Verified:

  • All 14 existing tests pass (ctest 14/14)
  • --pid mode works
  • -- prog ... mode works
  • Repeatable options behave as before
  • Argument validation semantics unchanged

The CodeFactor issue is in popl.hpp itself (a vendored third-party header), not in any code introduced by this PR.

- Vendor popl.hpp as a single-header dependency
- Replace manual parsing logic with popl::OptionParser
- Preserve all existing CLI behavior and defaults
- Maintain repeatable options, --pid and -- prog modes
- All 14 existing tests pass (ctest 14/14)
@iareARiES
Copy link
Author

Hi @graeme-a-stewart , this PR is ready for review. Please let me know if any changes are required.

@graeme-a-stewart
Copy link
Member

Thank you @iareARiES. I have been in a workshop this week, but next week I will review this.

@graeme-a-stewart
Copy link
Member

Just a quick observation - you have committed some files that should not be in the repository. Please remove them. Thanks.

@iareARiES
Copy link
Author

@graeme-a-stewart Thanks for pointing that out.
Removed the generated files and updated the branch accordingly.

Copy link
Member

@graeme-a-stewart graeme-a-stewart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pointed up a few places where the code can be improved, but broadly looking good @iareARiES.

// See https://github.com/HSF/prmon

#include <getopt.h>
#include "popl.hpp"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small point: Just in terms of header ordering, as popl.hpp is now a local header, if should be moved to third group of headers, which are the other local headers (and ordered alphabetically).

"o", "log-filename", "Filename for logging", "prmon.log");
auto opt_interval = op.add<popl::Value<unsigned int>>(
"i", "interval", "Seconds between samples", 30);
auto opt_suppress = op.add<popl::Switch>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be more specific, I would call the POPL variable here opt_suppress_hw_info.

"prmon is a process monitor program that records runtime data\n"
"from a process and its children, writing time stamped values\n"
"for resource consumption into a logfile and a JSON summary\n"
"format when the process exits.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As POPL adds a semicolon after this descriptive text, it looks nicer if you remove the final full stop.

"format when the process exits.");

auto opt_pid = op.add<popl::Value<int>>(
"p", "pid", "Monitored process ID", -1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the default -1 value - it looks odd when POPL prints this meaningless default. You use opt_pid->is_set(); below anyway and can adapt the logic to adopt an internal default for pid.

break;
}
// Extract values from parsed options
pid_t pid = opt_pid->value();
Copy link
Member

@graeme-a-stewart graeme-a-stewart Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like:

pid_t pid = -1;
bool got_pid = opt_pid->is_set();
if (got_pid) {
    pid = opt_pid->value();
}

Is better and avoids exposing a meaningless default to the user.

No functional changes were made.
@iareARiES
Copy link
Author

@graeme-a-stewart Thanks for the Review
I've addressed the requested changes:

  • Moved popl.hpp to the local header group (alphabetical order)
  • Renamed opt_suppress to opt_suppress_hw_info
  • Removed the trailing period from the OptionParser description
  • Removed the default -1 from --pid
  • Updated PID handling to use opt_pid->is_set() with an internal default

No functional changes were made.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants