ref: 6d1def25085dd4cbabde122df3d9dc1b6b0e087a
parent: 0d4a3fdc1e339e5269a08d24bcba780e247ca327
author: zamfofex <zamfofex@twdb.moe>
date: Sat Jan 11 20:58:41 EST 2025
make infrastructural improvements
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@
- simple evaluation based on PSTs
- MCTS (Monte Carlo tree search)
-- cute custom UCI TUIs
+- cute custom UCI TUI
- custom Lichess integration
- custom IRC integration
@@ -46,9 +46,9 @@
These are things that might be resolved eventually.
-- the TUIs do not let you underpromote
+- the TUI does not let you underpromote
- no support for `go depth`, `go infinite`, `go mate`
-- no FEN validation (may lead to potential exploits)
+- no support for some seldom used UCI features
download
---
@@ -60,12 +60,12 @@
Contributions to moonfish are always welcome! Whether you just have thoughts to share, or you want to improve its source code, any kind of help is vastly appreciated!
-Contributions (complaints, ideas, thoughts, patches, etc.) may be submitted via email to <zamfofex@twdb.moe> or shared in its IRC channel ([#moonfish] on [Libera.Chat]).
+Contributions (complaints, ideas, thoughts, patches, etc.) may be submitted via email to <zamfofex@twdb.moe> or shared in its IRC channel ([#moonfish] on [Libera Chat]).
- Note: The IRC channel is also bridged to Discord. (Please ask on IRC for a Discord invite.)
- Note: There is also a [#moonfish-miscellany] channel for general off‐topic conversations.
-[Libera.Chat]: <https://libera.chat>
+[Libera Chat]: <https://libera.chat>
[#moonfish]: <https://web.libera.chat/#moonfish>
[#moonfish-miscellany]: <https://web.libera.chat/#moonfish-miscellany>
@@ -103,7 +103,7 @@
make analyse
~~~
-“analyse” is a TUIs that allows you to analyse chess games with UCI bots.
+“analyse” is a TUI that allows you to analyse chess games with UCI bots.
After compiling and running it, you may use the mouse to click and move pieces around. (So, they require mouse support from your terminal.)
@@ -140,7 +140,7 @@
./chat -N irc.example.net -C '#my-channel,#other-channel' -M chess-bot stockfish
~~~
-It is only possible to connect to networks using TLS. The default nickname is “moonfish”, and it will connect by default to #moonfish on [Libera.Chat].
+It is only possible to connect to networks using TLS. The default nickname is “moonfish”, and it will connect by default to #moonfish on [Libera Chat].
using “lichess”
---
--- a/main.c
+++ b/main.c
@@ -360,7 +360,7 @@
}
if (!strcmp(arg, "uci")) {- printf("id name moonfish\n");+ printf("id name moonfish " moonfish_version "\n"); printf("id author zamfofex\n"); for (i = 0 ; options[i].name != NULL ; i++) { printf("option name %s type %s default %d min %d max %d\n", options[i].name, options[i].type, options[i].value, options[i].min, options[i].max);--- a/moonfish.h
+++ b/moonfish.h
@@ -4,6 +4,8 @@
#ifndef MOONFISH
#define MOONFISH
+#define moonfish_version "indev"
+
/* moonfish is a very simple chess bot written in C89 (ANSI C) */
/* in moonfish, pieces are each represented as a single 8-bit integer (char) */
@@ -149,7 +151,6 @@
/* uses the position from the given FEN, mutating the given position */
/* returns 0 if the FEN could be parsed */
/* returns 1 if the FEN could not be parsed (the position becomes unusable then!) */
-/* validation is very loose, so the FEN should be known to be good, otherwise this might cause unexpected results */
int moonfish_from_fen(struct moonfish_chess *chess, char *fen);
/* converts the given position to FEN */
--- a/tools/analyse.c
+++ b/tools/analyse.c
@@ -701,11 +701,22 @@
int main(int argc, char **argv)
{static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- static char *format = "<UCI-options>... [--] <cmd> <args>...";
- static struct moonfish_arg args[] = {- {"F", "fen", "<FEN>", NULL, "the position to analyse"},- {"G", "pgn", "<file-name>", NULL, "PGN game to load"},- {NULL, NULL, NULL, NULL, NULL},+ static struct moonfish_command cmd = {+ "analyse chess positions with a UCI bot",
+ "<UCI-opts>... [--] <cmd> <args>...",
+ {+ {"F", "fen", "<FEN>", NULL, "position to analyse"},+ {"G", "pgn", "<file-name>", NULL, "PGN game to load"},+ },
+ {+ {"lc0", "analyse a game using Leela"},+ {"stockfish", "analyse a game using Stockfish"},+ {"UCI_ShowWDL=true lc0", "pass a UCI option to the bot"},+ {"lc0 --show-wdl", "pass an argument to the bot"},+ {"-G game.pgn lc0", "load a PGN game for analysis"},+ },
+ {{NULL, NULL, NULL}},+ {"this is a TUI, use the mouse to move the pieces"},};
struct moonfish_fancy *fancy;
@@ -725,12 +736,12 @@
/* handle command line arguments */
- command = moonfish_args(args, format, argc, argv);
+ command = moonfish_args(&cmd, argc, argv);
command_count = argc - (command - argv);
- if (command_count < 1) moonfish_usage(args, format, argv[0]);
+ if (command_count < 1) moonfish_usage(&cmd, argv[0]);
options = command;
- if (args[0].value != NULL && args[1].value != NULL) moonfish_usage(args, format, argv[0]);
+ if (cmd.args[0].value != NULL && cmd.args[1].value != NULL) moonfish_usage(&cmd, argv[0]);
for (;;) {@@ -737,18 +748,18 @@
value = strchr(*command, '=');
if (value == NULL) break;
- if (strchr(*command, '\n') != NULL || strchr(*command, '\r') != NULL) moonfish_usage(args, format, argv[0]);
+ if (strchr(*command, '\n') != NULL || strchr(*command, '\r') != NULL) moonfish_usage(&cmd, argv[0]);
command_count--;
command++;
- if (command_count <= 0) moonfish_usage(args, format, argv[0]);
+ if (command_count <= 0) moonfish_usage(&cmd, argv[0]);
}
if (!strcmp(*command, "--")) {command_count--;
command++;
- if (command_count <= 0) moonfish_usage(args, format, argv[0]);
+ if (command_count <= 0) moonfish_usage(&cmd, argv[0]);
}
/* initialise data structures */
@@ -790,16 +801,16 @@
moonfish_chess(&fancy->plies[0].chess);
- if (args[0].value != NULL) {- fancy->fen = args[0].value;
+ if (cmd.args[0].value != NULL) {+ fancy->fen = cmd.args[0].value;
if (moonfish_from_fen(&fancy->plies[0].chess, fancy->fen)) {- moonfish_usage(args, format, argv[0]);
+ moonfish_usage(&cmd, argv[0]);
}
}
- if (args[1].value != NULL) {+ if (cmd.args[1].value != NULL) {- file = fopen(args[1].value, "r");
+ file = fopen(cmd.args[1].value, "r");
if (file == NULL) { perror("fopen");return 1;
--- a/tools/chat.c
+++ b/tools/chat.c
@@ -324,28 +324,41 @@
int main(int argc, char **argv)
{- static char *format = "<UCI-options> [--] <cmd> <args>...";
- static struct moonfish_arg args[] = {- {"N", "host", "<name>", "irc.libera.chat", "network host name (default: 'irc.libera.chat')"},- {"P", "port", "<port>", "6697", "network port (default: '6697')"},- {"M", "nick", "<nickname>", "moonfish", "the bot's nickname (default: 'moonfish')"},- {"C", "channel", "<channels>", "#moonfish", "channels to join (default: '#moonfish')"},- {NULL, NULL, NULL, NULL, NULL},+ static struct moonfish_command cmd = {+ "integrate a UCI bot with IRC",
+ "<UCI-opts>... [--] <cmd> <args>...",
+ {+ {"N", "host", "<name>", "irc.libera.chat", "network host (default: Libera Chat)"},+ {"P", "port", "<port>", "6697", "network port (default: '6697')"},+ {"M", "nick", "<nickname>", "moonfish", "bot's nickname (default: 'moonfish')"},+ {"C", "channel", "<channels>", "#moonfish", "channels to join (default: '#moonfish')"},+ },
+ {+ {"-M Leela lc0", "choose a nickname"},+ {"-N example.net -C '#hey' lc0", "join a given channel"},+ {"-C '#moonfish,##hey' moonfish", "join multiple channels"},+ },
+ {+ {"moonfish_chat_password", "<password>", "password for the IRC bot"},+ },
+ {+ "this will connect through TLS (using TCP directly is not supported)",
+ },
};
char **options, **command;
/* todo: validate nickname & channels */
- options = moonfish_args(args, format, argc, argv);
+ options = moonfish_args(&cmd, argc, argv);
command = options;
for (;;) {- if (*command == NULL) moonfish_usage(args, format, argv[0]);
+ if (*command == NULL) moonfish_usage(&cmd, argv[0]);
if (strchr(*command, '=') == NULL) break;
command++;
}
if (!strcmp(*command, "--")) command++;
- moonfish_chat(command, options, args[0].value, args[1].value, args[2].value, args[3].value);
+ moonfish_chat(command, options, cmd.args[0].value, cmd.args[1].value, cmd.args[2].value, cmd.args[3].value);
return 1;
}
--- a/tools/https.c
+++ b/tools/https.c
@@ -140,15 +140,12 @@
return 1;
}
- for (;;) {+ while (*line != 0) {free(line);
line = moonfish_read_line(tls);
- if (*line == 0) {- free(line);
- break;
- }
}
+ free(line);
return 0;
}
--- a/tools/lichess.c
+++ b/tools/lichess.c
@@ -483,12 +483,28 @@
int main(int argc, char **argv)
{- static char *format = "<UCI-options> [--] <cmd> <args>...";
- static struct moonfish_arg args[] = {- {"N", "host", "<name>", "lichess.org", "Lichess' host name (default: 'lichess.org')"},- {"P", "port", "<port>", "443", "Lichess' port (default: '443')"},- {"X", "ponder", NULL, NULL, "whether to think during the opponent's turn"},- {NULL, NULL, NULL, NULL, NULL},+ static struct moonfish_command cmd = {+ "integrate a UCI bot with Lichess",
+ "<UCI-opts>... [--] <cmd> <args>...",
+ {+ {"N", "host", "<name>", "lichess.org", "Lichess' host name (default: 'lichess.org')"},+ {"P", "port", "<port>", "443", "Lichess' port (default: '443')"},+ {"X", "ponder", NULL, NULL, "think during the opponent's turn"},+ {NULL, NULL, NULL, NULL, NULL},+ },
+ {+ {"moonfish", "use moonfish as a Lichess bot"},+ {"-X lc0", "use Leela and enable pondering"},+ {"-N example.org lc0", "connect to another Lichess instance"},+ },
+ {+ {"lichess_token", "<token>", "personal access token for Lichess (required)"},+ },
+ {+ "this will connect through HTTPS (using HTTP without TLS is not supported)",
+ "pondering uses UCI 'go infinite' rather than 'go ponder'",
+ "this only accepts incoming challenges without matchmaking",
+ },
};
char *token;
@@ -500,11 +516,9 @@
struct sigaction action;
char *value;
- /* handle command line arguments */
-
- command = moonfish_args(args, format, argc, argv);
+ command = moonfish_args(&cmd, argc, argv);
command_count = argc - (command - argv);
- if (command_count < 1) moonfish_usage(args, format, argv[0]);
+ if (command_count < 1) moonfish_usage(&cmd, argv[0]);
options = command;
for (;;) {@@ -512,29 +526,29 @@
value = strchr(*command, '=');
if (value == NULL) break;
- if (strchr(*command, '\n') != NULL || strchr(*command, '\r') != NULL) moonfish_usage(args, format, argv[0]);
+ if (strchr(*command, '\n') != NULL || strchr(*command, '\r') != NULL) moonfish_usage(&cmd, argv[0]);
command_count--;
command++;
- if (command_count <= 0) moonfish_usage(args, format, argv[0]);
+ if (command_count <= 0) moonfish_usage(&cmd, argv[0]);
}
if (!strcmp(*command, "--")) {command_count--;
command++;
- if (command_count <= 0) moonfish_usage(args, format, argv[0]);
+ if (command_count <= 0) moonfish_usage(&cmd, argv[0]);
}
token = getenv("lichess_token"); if (token == NULL || token[0] == 0) {- fprintf(stderr, "%s: Lichess token not provided\n", argv[0]);
+ fprintf(stderr, "Lichess token not provided\n");
return 1;
}
for (i = 0 ; token[i] != 0 ; i++) { if (token[i] <= 0x20 || token[i] >= 0x7F) {- fprintf(stderr, "%s: invalid token provided for Lichess\n", argv[0]);
+ fprintf(stderr, "invalid token provided for Lichess\n");
return 1;
}
}
@@ -548,14 +562,14 @@
return 1;
}
- tls = moonfish_connect(args[0].value, args[1].value);
- moonfish_request(tls, args[0].value, "GET /api/stream/event", token, NULL, 0);
+ tls = moonfish_connect(cmd.args[0].value, cmd.args[1].value);
+ moonfish_request(tls, cmd.args[0].value, "GET /api/stream/event", token, NULL, 0);
if (moonfish_response(tls)) {fprintf(stderr, "could not request event stream\n");
return 1;
}
- username = moonfish_username(args[0].value, args[1].value, token);
- moonfish_handle_events(tls, args[0].value, args[1].value, token, options, command, username, args[2].value != NULL ? 1 : 0);
+ username = moonfish_username(cmd.args[0].value, cmd.args[1].value, token);
+ moonfish_handle_events(tls, cmd.args[0].value, cmd.args[1].value, token, options, command, username, cmd.args[2].value != NULL ? 1 : 0);
return 1;
}
--- a/tools/perft.c
+++ b/tools/perft.c
@@ -33,10 +33,15 @@
int main(int argc, char **argv)
{- static char *format = "<depth>";
- static struct moonfish_arg args[] = {- {"F", "fen", "<FEN>", NULL, "starting position for the game"},- {NULL, NULL, NULL, NULL, NULL},+ static struct moonfish_command cmd = {+ "show count of positions reachable from a given position (in 'n' plies)",
+ "<depth>",
+ {+ {"F", "fen", "<FEN>", NULL, "starting position for the game"},+ },
+ {{NULL, NULL}},+ {{NULL, NULL, NULL}},+ {NULL},};
int depth;
@@ -43,13 +48,13 @@
struct moonfish_chess chess;
char **args2;
- args2 = moonfish_args(args, format, argc, argv);
- if (args2 - argv != argc - 1) moonfish_usage(args, format, argv[0]);
+ args2 = moonfish_args(&cmd, argc, argv);
+ if (args2 - argv != argc - 1) moonfish_usage(&cmd, argv[0]);
- if (moonfish_int(args2[0], &depth) || depth < 0) moonfish_usage(args, format, argv[0]);
+ if (moonfish_int(args2[0], &depth) || depth < 0) moonfish_usage(&cmd, argv[0]);
moonfish_chess(&chess);
- if (args[0].value != NULL && moonfish_from_fen(&chess, args[0].value)) moonfish_usage(args, format, argv[0]);
+ if (cmd.args[0].value != NULL && moonfish_from_fen(&chess, cmd.args[0].value)) moonfish_usage(&cmd, argv[0]);
printf("perft %d: %ld\n", depth, moonfish_perft(&chess, depth));--- a/tools/tools.h
+++ b/tools/tools.h
@@ -14,6 +14,26 @@
char *description;
};
+struct moonfish_env {+ char *name;
+ char *format;
+ char *description;
+};
+
+struct moonfish_example {+ char *args;
+ char *description;
+};
+
+struct moonfish_command {+ char *description;
+ char *rest;
+ struct moonfish_arg args[16];
+ struct moonfish_example examples[16];
+ struct moonfish_env env[16];
+ char *notes[16];
+};
+
struct moonfish_chess;
struct moonfish_move;
@@ -21,8 +41,8 @@
char *moonfish_next(FILE *file);
char *moonfish_wait(FILE *file, char *name);
-char **moonfish_args(struct moonfish_arg *args, char *rest_format, int argc, char **argv);
-void moonfish_usage(struct moonfish_arg *args, char *rest_format, char *argv0);
+char **moonfish_args(struct moonfish_command *cmd, int argc, char **argv);
+void moonfish_usage(struct moonfish_command *cmd, char *argv0);
int moonfish_int(char *arg, int *result);
--- a/tools/utils.c
+++ b/tools/utils.c
@@ -6,12 +6,14 @@
#include <string.h>
#include <errno.h>
#include <limits.h>
+#include <fcntl.h>
+#include "../moonfish.h"
#include "tools.h"
static void moonfish_fork(char **argv, int *in_fd, int *out_fd, char *directory)
{- int p1[2], p2[2];
+ int p1[2], p2[2], fd;
int pid;
long int count, i;
@@ -43,7 +45,13 @@
exit(1);
}
- if (dup2(p1[0], 0) != 0 || dup2(p2[1], 1) != 1 || dup2(p2[1], 2) != 2) {+ fd = open("/dev/null", O_WRONLY);+ if (fd < 0) {+ perror("open");+ exit(1);
+ }
+
+ if (dup2(p1[0], 0) != 0 || dup2(p2[1], 1) != 1 || dup2(fd, 2) != 2) { perror("dup2");exit(1);
}
@@ -123,7 +131,7 @@
return 0;
}
-static void moonfish_usage_to(struct moonfish_arg *args, char *rest_format, char *argv0, FILE *out)
+void moonfish_usage(struct moonfish_command *cmd, char *argv0)
{int i;
int col1, col2, n;
@@ -130,77 +138,149 @@
if (argv0 == NULL) argv0 = "<program>";
+ if (cmd->args[0].letter == NULL && cmd->args[0].name == NULL) fprintf(stderr, "usage: %s", argv0);
+ else fprintf(stderr, "usage: %s <opts>...", argv0);
+ if (cmd->rest != NULL) fprintf(stderr, " [--] %s", cmd->rest);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "purpose: %s\n", cmd->description);
+
+ if (cmd->examples[0].description != NULL) {+
+ col1 = 0;
+
+ for (i = 0 ; cmd->examples[i].description != NULL ; i++) {+ n = strlen(cmd->examples[i].args);
+ if (n > col1) col1 = n;
+ }
+
+ fprintf(stderr, "examples:\n");
+ for (i = 0 ; cmd->examples[i].description != NULL ; i++) {+
+ n = strlen(cmd->examples[i].args);
+
+ fprintf(stderr, " ");
+ fprintf(stderr, "\x1B[36m%s", argv0);
+ if (cmd->examples[i].args != NULL) {+ fprintf(stderr, " %s", cmd->examples[i].args);
+ }
+
+ fprintf(stderr, "\x1B[0m");
+
+ while (n < col1) {+ fprintf(stderr, " ");
+ n++;
+ }
+
+ fprintf(stderr, " %s\n", cmd->examples[i].description);
+ }
+ }
+
col1 = 0;
col2 = 0;
- for (i = 0 ; args[i].letter != NULL || args[i].name != NULL ; i++) {+ for (i = 0 ; cmd->args[i].letter != NULL || cmd->args[i].name != NULL ; i++) {n = 0;
- if (args[i].letter != NULL) {- n += 1 + strlen(args[i].letter);
- if (args[i].format != NULL) n += strlen(args[i].format);
+ if (cmd->args[i].letter != NULL) {+ n += 1 + strlen(cmd->args[i].letter);
+ if (cmd->args[i].format != NULL) n += strlen(cmd->args[i].format);
}
if (n > col1) col1 = n;
n = 0;
- if (args[i].name != NULL) {- n += 2 + strlen(args[i].name);
- if (args[i].format != NULL) n += 1 + strlen(args[i].format);
+ if (cmd->args[i].name != NULL) {+ n += 2 + strlen(cmd->args[i].name);
+ if (cmd->args[i].format != NULL) n += 1 + strlen(cmd->args[i].format);
}
if (n > col2) col2 = n;
}
- if (args[0].letter == NULL && args[0].name == NULL) fprintf(out, "usage: %s", argv0);
- else fprintf(out, "usage: %s <options>...", argv0);
- if (rest_format != NULL) fprintf(out, " [--] %s", rest_format);
- fprintf(out, "\noptions:\n");
+ if (cmd->args[0].letter == NULL && cmd->args[0].name == NULL) return;
- if (args[0].letter == NULL && args[0].name == NULL) return;
+ fprintf(stderr, "options:\n");
- for (i = 0 ; args[i].letter != NULL || args[i].name != NULL ; i++) {+ for (i = 0 ; cmd->args[i].letter != NULL || cmd->args[i].name != NULL ; i++) {- fprintf(out, " ");
+ fprintf(stderr, " ");
n = 0;
- if (args[i].letter != NULL) {- n += 1 + strlen(args[i].letter);
- fprintf(out, "-%s", args[i].letter);
- if (args[i].format != NULL) {- n += strlen(args[i].format);
- fprintf(out, "\x1B[36m%s\x1B[0m", args[i].format);
+ if (cmd->args[i].letter != NULL) {+ n += 1 + strlen(cmd->args[i].letter);
+ fprintf(stderr, "-%s", cmd->args[i].letter);
+ if (cmd->args[i].format != NULL) {+ n += strlen(cmd->args[i].format);
+ fprintf(stderr, "\x1B[36m%s\x1B[0m", cmd->args[i].format);
}
}
- if (args[i].letter != NULL && args[i].name != NULL) fprintf(out, ", ");
- else fprintf(out, " ");
+ if (cmd->args[i].letter != NULL && cmd->args[i].name != NULL) fprintf(stderr, ", ");
+ else fprintf(stderr, " ");
while (n < col1) {- fprintf(out, " ");
+ fprintf(stderr, " ");
n++;
}
n = 0;
- if (args[i].name != NULL) {- n += 2 + strlen(args[i].name);
- fprintf(out, "--%s", args[i].name);
- if (args[i].format != NULL) {- n += 1 + strlen(args[i].format);
- fprintf(out, "=\x1B[36m%s\x1B[0m", args[i].format);
+ if (cmd->args[i].name != NULL) {+ n += 2 + strlen(cmd->args[i].name);
+ fprintf(stderr, "--%s", cmd->args[i].name);
+ if (cmd->args[i].format != NULL) {+ n += 1 + strlen(cmd->args[i].format);
+ fprintf(stderr, "=\x1B[36m%s\x1B[0m", cmd->args[i].format);
}
}
- if (args[i].description != NULL) {-
+ if (cmd->args[i].description != NULL) { while (n < col2) {- fprintf(out, " ");
+ fprintf(stderr, " ");
n++;
}
-
- fprintf(out, " %s", args[i].description);
+ fprintf(stderr, " %s", cmd->args[i].description);
}
- fprintf(out, "\n");
+ fprintf(stderr, "\n");
}
+
+ if (cmd->env[0].name != NULL) {+
+ col1 = 0;
+
+ for (i = 0 ; cmd->env[i].name != NULL ; i++) {+ n = strlen(cmd->env[i].name) + strlen(cmd->env[i].format);
+ if (n > col1) col1 = n;
+ }
+
+ fprintf(stderr, "environment:\n");
+ for (i = 0 ; cmd->env[i].name != NULL ; i++) {+
+ n = strlen(cmd->env[i].name) + strlen(cmd->env[i].format);
+
+ fprintf(stderr, " ");
+ fprintf(stderr, "%s=\x1B[36m%s\x1B[0m", cmd->env[i].name, cmd->env[i].format);
+
+ while (n < col1) {+ fprintf(stderr, " ");
+ n++;
+ }
+
+ fprintf(stderr, " %s\n", cmd->env[i].description);
+ }
+ }
+
+ if (cmd->notes[0] != NULL) {+ fprintf(stderr, "notes:\n");
+ for (i = 0 ; cmd->notes[i] != NULL ; i++) fprintf(stderr, " %s\n", cmd->notes[i]);
+ }
+
+ fprintf(stderr, "version:\n");
+ fprintf(stderr, " %s is part of \x1B[36mmoonfish " moonfish_version "\x1B[0m\n", argv0);
+ fprintf(stderr, " copyright 2025 zamfofex (AGPL, v3 or later)\n");
+ fprintf(stderr, " report bugs to \x1B[36mzamfofex@twdb.moe\x1B[0m\n");
+ fprintf(stderr, " source code at \x1B[36mhttps://git.sr.ht/~zamfofex/moonfish\x1B[0m\n");
+
+ exit(1);
}
static int moonfish_letter_arg(struct moonfish_arg *args, char *arg, int *argc, char ***argv)
@@ -282,7 +362,7 @@
return 1;
}
-char **moonfish_args(struct moonfish_arg *args, char *rest_format, int argc, char **argv)
+char **moonfish_args(struct moonfish_command *cmd, int argc, char **argv)
{char *arg, *argv0;
@@ -298,28 +378,19 @@
arg = *argv;
if (!strcmp(arg, "-")) return argv;
- if (!strcmp(arg, "--") && rest_format != NULL) return argv + 1;
-
- if (!strcmp(arg, "--help") || !strcmp(arg, "-h") || !strcmp(arg, "-H")) {- moonfish_usage_to(args, rest_format, argv0, stdout);
- exit(0);
+ if (!strcmp(arg, "--")) {+ if (cmd->rest == NULL) moonfish_usage(cmd, argv0);
+ return argv + 1;
}
-
if (arg[0] != '-') return argv;
arg++;
if (arg[0] == '-') {arg++;
- if (moonfish_name_arg(args, arg, &argc, &argv)) moonfish_usage(args, rest_format, argv0);
+ if (moonfish_name_arg(cmd->args, arg, &argc, &argv)) moonfish_usage(cmd, argv0);
continue;
}
- if (moonfish_letter_arg(args, arg, &argc, &argv)) moonfish_usage(args, rest_format, argv0);
+ if (moonfish_letter_arg(cmd->args, arg, &argc, &argv)) moonfish_usage(cmd, argv0);
}
-}
-
-void moonfish_usage(struct moonfish_arg *args, char *rest_format, char *argv0)
-{- moonfish_usage_to(args, rest_format, argv0, stderr);
- exit(1);
}
--
⑨