<commit_before>#include <cstdlib>
#include <iostream>
#include <memory>
#include <stdexcept>

#include "xopt.h"

#include "cli.h"

using namespace std;

struct free_ptr {
	void operator()(void *x) {
		free(x);
	}
};

void add_zone_path(const char *path, void *data, const xoptOption *option, bool longArg, const char **err) {
	(void) option;
	(void) longArg;

	arua::config *cfg = (arua::config *)data;

	filesystem::path fpath = path;
	if (!fpath.exists()) {
		*err = ("zone path does not exist: " + fpath.str()).c_str();
		return;
	}

	if (!fpath.is_directory()) {
		*err = ("zone path is not a directory: " + fpath.str()).c_str();
		return;
	}

	cfg->zones.insert(fpath);
}

static const xoptOption options[] = {
	{
		"zone",
		'Z',
		0, // we don't care about it in our setter function
		&add_zone_path,
		XOPT_TYPE_STRING,
		0,
		"Specifies a zone search path"
	},
	{
		"help",
		'?',
		offsetof(arua::config, help),
		0,
		XOPT_TYPE_BOOL,
		0,
		"Shows this help message"
	}
};

bool arua::build_config(int argc, const char *argv[], arua::config &cfg) {
	const char *err;

	unique_ptr<xoptContext, free_ptr> ctx(xopt_context("aruab", options, XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, &err));
	if (err) {
		throw runtime_error(err);
	}

	const char **extrav = 0;
	int extrac = xopt_parse(ctx.get(), argc, argv, &cfg, &extrav, &err);
	if (err) {
		free(extrav);
		throw runtime_error(err);
	}
<commit_msg>fix cli autohelp by terminating options list properly<commit_after>#include <cstdlib>
#include <iostream>
#include <memory>
#include <stdexcept>

#include "xopt.h"

#include "cli.h"

using namespace std;

struct free_ptr {
	void operator()(void *x) {
		free(x);
	}
};

void add_zone_path(const char *path, void *data, const xoptOption *option, bool longArg, const char **err) {
	(void) option;
	(void) longArg;

	arua::config *cfg = (arua::config *)data;

	filesystem::path fpath = path;
	if (!fpath.exists()) {
		*err = ("zone path does not exist: " + fpath.str()).c_str();
		return;
	}

	if (!fpath.is_directory()) {
		*err = ("zone path is not a directory: " + fpath.str()).c_str();
		return;
	}

	cfg->zones.insert(fpath);
}

static const xoptOption options[] = {
	{
		"zone",
		'Z',
		0, // we don't care about it in our setter function
		&add_zone_path,
		XOPT_TYPE_STRING,
		0,
		"Specifies a zone search path"
	},
	{
		"help",
		'?',
		offsetof(arua::config, help),
		0,
		XOPT_TYPE_BOOL,
		0,
		"Shows this help message"
	},
	XOPT_NULLOPTION
};

bool arua::build_config(int argc, const char *argv[], arua::config &cfg) {
	const char *err;

	unique_ptr<xoptContext, free_ptr> ctx(xopt_context("aruab", options, XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, &err));
	if (err) {
		throw runtime_error(err);
	}

	const char **extrav = 0;
	int extrac = xopt_parse(ctx.get(), argc, argv, &cfg, &extrav, &err);
	if (err) {
		free(extrav);
		throw runtime_error(err);
	}

{'fraction_non_alphanumeric': 0.16365531619179985, 'fraction_numerical': 0.0034746351633078527, 'mean_word_length': 4.2536496350364965, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1585043', 'n_tokens_mistral': 1210, 'n_tokens_neox': 1139, 'n_words': 290}