Template
112 lines
2.6 KiB
C
112 lines
2.6 KiB
C
/*
|
|
* cli.c - argument parsing for the stupidtools entrypoint.
|
|
*
|
|
* Manual parsing on purpose: the flag surface is tiny and fully under
|
|
* our control, so there is no need for getopt's permutation rules or
|
|
* its platform quirks. Unknown options are usage errors (exit 2) with
|
|
* the usage text on stderr; a missing buildfile is a runtime error
|
|
* (exit 1). -- terminates option parsing so a buildfile whose name
|
|
* starts with '-' stays addressable.
|
|
*
|
|
* Copyright (c) 2026 huntedbytheirs
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "cli.h"
|
|
|
|
#include <string.h>
|
|
|
|
static const char *
|
|
program_name(const char *argv0)
|
|
{
|
|
if (argv0 == NULL || argv0[0] == '\0') {
|
|
return "stupidtools";
|
|
}
|
|
return argv0;
|
|
}
|
|
|
|
static int
|
|
is_option(const char *arg)
|
|
{
|
|
return arg[0] == '-' && arg[1] != '\0' && strcmp(arg, "-") != 0;
|
|
}
|
|
|
|
void
|
|
cli_print_usage(FILE *stream, const char *program)
|
|
{
|
|
fprintf(stream,
|
|
"Usage: %s [OPTIONS] <buildfile.kdl>\n"
|
|
"\n"
|
|
"Reads a KDL build file and emits a POSIX-sh ./configure script.\n"
|
|
"\n"
|
|
"Options:\n"
|
|
" -h, --help show this help and exit\n"
|
|
" -V, --version print version and exit\n"
|
|
"\n"
|
|
"Note: buildfile processing is not yet implemented.\n",
|
|
program);
|
|
}
|
|
|
|
/* Take the next positional argument, reporting usage errors to stderr.
|
|
* Returns CLI_ACTION_ERROR (with usage printed) or CLI_ACTION_RUN. */
|
|
static enum cli_action
|
|
take_positional(const char *arg, struct cli_opts *opts)
|
|
{
|
|
if (opts->buildfile != NULL) {
|
|
fprintf(stderr, "%s: unexpected extra argument '%s'\n",
|
|
opts->program, arg);
|
|
cli_print_usage(stderr, opts->program);
|
|
return CLI_ACTION_ERROR;
|
|
}
|
|
opts->buildfile = arg;
|
|
return CLI_ACTION_RUN;
|
|
}
|
|
|
|
enum cli_action
|
|
cli_parse(int argc, char **argv, struct cli_opts *opts)
|
|
{
|
|
enum cli_action action;
|
|
int i;
|
|
|
|
opts->program = program_name(argc > 0 ? argv[0] : NULL);
|
|
opts->buildfile = NULL;
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
const char *arg = argv[i];
|
|
|
|
if (!is_option(arg)) {
|
|
action = take_positional(arg, opts);
|
|
if (action != CLI_ACTION_RUN) {
|
|
return action;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(arg, "--") == 0) {
|
|
for (i++; i < argc; i++) {
|
|
action = take_positional(argv[i], opts);
|
|
if (action != CLI_ACTION_RUN) {
|
|
return action;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
|
|
cli_print_usage(stdout, opts->program);
|
|
return CLI_ACTION_HELP;
|
|
}
|
|
|
|
if (strcmp(arg, "-V") == 0 || strcmp(arg, "--version") == 0) {
|
|
return CLI_ACTION_VERSION;
|
|
}
|
|
|
|
fprintf(stderr, "%s: unrecognized option '%s'\n",
|
|
opts->program, arg);
|
|
cli_print_usage(stderr, opts->program);
|
|
return CLI_ACTION_ERROR;
|
|
}
|
|
|
|
return CLI_ACTION_RUN;
|
|
}
|