mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-23 08:13:08 +08:00
split builtin random into its own module
This commit is contained in:
parent
e7f87c08e1
commit
1c91ec9dfa
49
Makefile.in
49
Makefile.in
|
@ -101,6 +101,7 @@ HAVE_DOXYGEN=@HAVE_DOXYGEN@
|
||||||
FISH_OBJS := obj/autoload.o obj/builtin.o obj/builtin_bind.o obj/builtin_block.o \
|
FISH_OBJS := obj/autoload.o obj/builtin.o obj/builtin_bind.o obj/builtin_block.o \
|
||||||
obj/builtin_commandline.o obj/builtin_emit.o obj/builtin_functions.o \
|
obj/builtin_commandline.o obj/builtin_emit.o obj/builtin_functions.o \
|
||||||
obj/builtin_history.o obj/builtin_status.o obj/builtin_read.o \
|
obj/builtin_history.o obj/builtin_status.o obj/builtin_read.o \
|
||||||
|
obj/builtin_random.o \
|
||||||
obj/builtin_complete.o obj/builtin_jobs.o obj/builtin_printf.o \
|
obj/builtin_complete.o obj/builtin_jobs.o obj/builtin_printf.o \
|
||||||
obj/builtin_set.o obj/builtin_set_color.o obj/builtin_string.o \
|
obj/builtin_set.o obj/builtin_set_color.o obj/builtin_string.o \
|
||||||
obj/builtin_test.o obj/builtin_ulimit.o obj/color.o obj/common.o \
|
obj/builtin_test.o obj/builtin_ulimit.o obj/color.o obj/common.o \
|
||||||
|
@ -946,17 +947,18 @@ v = $(V$(V))
|
||||||
obj/autoload.o: config.h src/autoload.h src/common.h src/fallback.h
|
obj/autoload.o: config.h src/autoload.h src/common.h src/fallback.h
|
||||||
obj/autoload.o: src/signal.h src/lru.h src/env.h src/exec.h src/wutil.h
|
obj/autoload.o: src/signal.h src/lru.h src/env.h src/exec.h src/wutil.h
|
||||||
obj/builtin.o: config.h src/signal.h src/builtin.h src/common.h
|
obj/builtin.o: config.h src/signal.h src/builtin.h src/common.h
|
||||||
obj/builtin.o: src/fallback.h src/builtin_bind.h src/builtin_block.h src/builtin_functions.h
|
obj/builtin.o: src/fallback.h src/builtin_bind.h src/builtin_block.h
|
||||||
obj/builtin.o: src/builtin_commandline.h src/builtin_complete.h src/builtin_history.h
|
obj/builtin.o: src/builtin_commandline.h src/builtin_complete.h
|
||||||
obj/builtin.o: src/builtin_emit.h src/builtin_jobs.h src/builtin_printf.h
|
obj/builtin.o: src/builtin_emit.h src/builtin_functions.h
|
||||||
obj/builtin.o: src/builtin_set.h src/builtin_set_color.h src/builtin_string.h
|
obj/builtin.o: src/builtin_history.h src/builtin_jobs.h src/builtin_printf.h
|
||||||
obj/builtin.o: src/builtin_test.h src/builtin_ulimit.h src/complete.h
|
obj/builtin.o: src/builtin_random.h src/builtin_read.h src/builtin_set.h
|
||||||
obj/builtin.o: src/env.h src/event.h src/exec.h src/expand.h
|
obj/builtin.o: src/builtin_set_color.h src/builtin_status.h
|
||||||
obj/builtin.o: src/parse_constants.h src/function.h src/highlight.h
|
obj/builtin.o: src/builtin_string.h src/builtin_test.h src/builtin_ulimit.h
|
||||||
obj/builtin.o: src/color.h src/history.h src/wutil.h src/intern.h src/io.h
|
obj/builtin.o: src/complete.h src/env.h src/event.h src/exec.h src/function.h
|
||||||
obj/builtin.o: src/parse_util.h src/tokenizer.h src/parser.h src/parse_tree.h
|
obj/builtin.o: src/intern.h src/io.h src/parse_constants.h src/parse_util.h
|
||||||
|
obj/builtin.o: src/tokenizer.h src/parser.h src/expand.h src/parse_tree.h
|
||||||
obj/builtin.o: src/proc.h src/parser_keywords.h src/path.h src/reader.h
|
obj/builtin.o: src/proc.h src/parser_keywords.h src/path.h src/reader.h
|
||||||
obj/builtin.o: src/wcstringutil.h src/wgetopt.h
|
obj/builtin.o: src/highlight.h src/color.h src/wgetopt.h src/wutil.h
|
||||||
obj/builtin_bind.o: config.h src/builtin.h src/common.h src/fallback.h
|
obj/builtin_bind.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
obj/builtin_bind.o: src/signal.h src/builtin_bind.h src/input.h src/env.h
|
obj/builtin_bind.o: src/signal.h src/builtin_bind.h src/input.h src/env.h
|
||||||
obj/builtin_bind.o: src/io.h src/wgetopt.h src/wutil.h
|
obj/builtin_bind.o: src/io.h src/wgetopt.h src/wutil.h
|
||||||
|
@ -980,15 +982,33 @@ obj/builtin_complete.o: src/parse_tree.h src/proc.h src/reader.h
|
||||||
obj/builtin_complete.o: src/highlight.h src/color.h src/wgetopt.h src/wutil.h
|
obj/builtin_complete.o: src/highlight.h src/color.h src/wgetopt.h src/wutil.h
|
||||||
obj/builtin_emit.o: config.h src/builtin.h src/common.h src/fallback.h
|
obj/builtin_emit.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
obj/builtin_emit.o: src/signal.h src/builtin_emit.h src/event.h src/io.h
|
obj/builtin_emit.o: src/signal.h src/builtin_emit.h src/event.h src/io.h
|
||||||
obj/builtin_emit.o: src/parser.h src/expand.h src/parse_constants.h
|
|
||||||
obj/builtin_emit.o: src/parse_tree.h src/tokenizer.h src/proc.h
|
|
||||||
obj/builtin_emit.o: src/wgetopt.h src/wutil.h
|
obj/builtin_emit.o: src/wgetopt.h src/wutil.h
|
||||||
|
obj/builtin_functions.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
|
obj/builtin_functions.o: src/signal.h src/builtin_functions.h src/env.h
|
||||||
|
obj/builtin_functions.o: src/event.h src/function.h src/io.h
|
||||||
|
obj/builtin_functions.o: src/parser_keywords.h src/proc.h src/parse_tree.h
|
||||||
|
obj/builtin_functions.o: src/parse_constants.h src/tokenizer.h src/wgetopt.h
|
||||||
|
obj/builtin_functions.o: src/wutil.h
|
||||||
|
obj/builtin_history.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
|
obj/builtin_history.o: src/signal.h src/builtin_history.h src/history.h
|
||||||
|
obj/builtin_history.o: src/wutil.h src/io.h src/reader.h src/complete.h
|
||||||
|
obj/builtin_history.o: src/highlight.h src/color.h src/env.h
|
||||||
|
obj/builtin_history.o: src/parse_constants.h src/wgetopt.h
|
||||||
obj/builtin_jobs.o: config.h src/builtin.h src/common.h src/fallback.h
|
obj/builtin_jobs.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
obj/builtin_jobs.o: src/signal.h src/io.h src/proc.h src/parse_tree.h
|
obj/builtin_jobs.o: src/signal.h src/io.h src/proc.h src/parse_tree.h
|
||||||
obj/builtin_jobs.o: src/parse_constants.h src/tokenizer.h src/wgetopt.h
|
obj/builtin_jobs.o: src/parse_constants.h src/tokenizer.h src/wgetopt.h
|
||||||
obj/builtin_jobs.o: src/wutil.h
|
obj/builtin_jobs.o: src/wutil.h
|
||||||
obj/builtin_printf.o: config.h src/builtin.h src/common.h src/fallback.h
|
obj/builtin_printf.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
obj/builtin_printf.o: src/signal.h src/io.h src/wutil.h
|
obj/builtin_printf.o: src/signal.h src/io.h src/wutil.h
|
||||||
|
obj/builtin_random.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
|
obj/builtin_random.o: src/signal.h src/builtin_random.h src/io.h
|
||||||
|
obj/builtin_random.o: src/wgetopt.h src/wutil.h
|
||||||
|
obj/builtin_read.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
|
obj/builtin_read.o: src/signal.h src/builtin_read.h src/complete.h src/env.h
|
||||||
|
obj/builtin_read.o: src/event.h src/expand.h src/parse_constants.h
|
||||||
|
obj/builtin_read.o: src/highlight.h src/color.h src/io.h src/proc.h
|
||||||
|
obj/builtin_read.o: src/parse_tree.h src/tokenizer.h src/reader.h
|
||||||
|
obj/builtin_read.o: src/wcstringutil.h src/wgetopt.h src/wutil.h
|
||||||
obj/builtin_set.o: config.h src/builtin.h src/common.h src/fallback.h
|
obj/builtin_set.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
obj/builtin_set.o: src/signal.h src/env.h src/expand.h src/parse_constants.h
|
obj/builtin_set.o: src/signal.h src/env.h src/expand.h src/parse_constants.h
|
||||||
obj/builtin_set.o: src/io.h src/proc.h src/parse_tree.h src/tokenizer.h
|
obj/builtin_set.o: src/io.h src/proc.h src/parse_tree.h src/tokenizer.h
|
||||||
|
@ -996,6 +1016,11 @@ obj/builtin_set.o: src/wgetopt.h src/wutil.h
|
||||||
obj/builtin_set_color.o: config.h src/builtin.h src/common.h src/fallback.h
|
obj/builtin_set_color.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
obj/builtin_set_color.o: src/signal.h src/color.h src/env.h src/io.h
|
obj/builtin_set_color.o: src/signal.h src/color.h src/env.h src/io.h
|
||||||
obj/builtin_set_color.o: src/output.h src/wgetopt.h src/wutil.h
|
obj/builtin_set_color.o: src/output.h src/wgetopt.h src/wutil.h
|
||||||
|
obj/builtin_status.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
|
obj/builtin_status.o: src/signal.h src/builtin_status.h src/io.h src/parser.h
|
||||||
|
obj/builtin_status.o: src/event.h src/expand.h src/parse_constants.h
|
||||||
|
obj/builtin_status.o: src/parse_tree.h src/tokenizer.h src/proc.h
|
||||||
|
obj/builtin_status.o: src/wgetopt.h src/wutil.h
|
||||||
obj/builtin_string.o: config.h src/builtin.h src/common.h src/fallback.h
|
obj/builtin_string.o: config.h src/builtin.h src/common.h src/fallback.h
|
||||||
obj/builtin_string.o: src/signal.h src/io.h src/parse_util.h
|
obj/builtin_string.o: src/signal.h src/io.h src/parse_util.h
|
||||||
obj/builtin_string.o: src/parse_constants.h src/tokenizer.h src/wgetopt.h
|
obj/builtin_string.o: src/parse_constants.h src/tokenizer.h src/wgetopt.h
|
||||||
|
|
154
src/builtin.cpp
154
src/builtin.cpp
|
@ -21,7 +21,6 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -31,7 +30,6 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <random>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -45,6 +43,7 @@
|
||||||
#include "builtin_history.h"
|
#include "builtin_history.h"
|
||||||
#include "builtin_jobs.h"
|
#include "builtin_jobs.h"
|
||||||
#include "builtin_printf.h"
|
#include "builtin_printf.h"
|
||||||
|
#include "builtin_random.h"
|
||||||
#include "builtin_read.h"
|
#include "builtin_read.h"
|
||||||
#include "builtin_set.h"
|
#include "builtin_set.h"
|
||||||
#include "builtin_set_color.h"
|
#include "builtin_set_color.h"
|
||||||
|
@ -897,157 +896,6 @@ int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_lis
|
||||||
return STATUS_CMD_OK;
|
return STATUS_CMD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The random builtin generates random numbers.
|
|
||||||
static int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|
||||||
int argc = builtin_count_args(argv);
|
|
||||||
|
|
||||||
static bool seeded = false;
|
|
||||||
static std::minstd_rand engine;
|
|
||||||
if (!seeded) {
|
|
||||||
// seed engine with 2*32 bits of random data
|
|
||||||
// for the 64 bits of internal state of minstd_rand
|
|
||||||
std::random_device rd;
|
|
||||||
std::seed_seq seed{rd(), rd()};
|
|
||||||
engine.seed(seed);
|
|
||||||
seeded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const wchar_t *short_options = L"h";
|
|
||||||
static const struct woption long_options[] = {{L"help", no_argument, NULL, 'h'},
|
|
||||||
{NULL, 0, NULL, 0}};
|
|
||||||
|
|
||||||
int opt;
|
|
||||||
wgetopter_t w;
|
|
||||||
while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
|
|
||||||
switch (opt) { //!OCLINT(too few branches)
|
|
||||||
case 'h': {
|
|
||||||
builtin_print_help(parser, streams, argv[0], streams.out);
|
|
||||||
return STATUS_CMD_OK;
|
|
||||||
}
|
|
||||||
case '?': {
|
|
||||||
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
|
||||||
return STATUS_INVALID_ARGS;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
DIE("unexpected retval from wgetopt_long");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int arg_count = argc - w.woptind;
|
|
||||||
long long start, end;
|
|
||||||
unsigned long long step;
|
|
||||||
bool choice = false;
|
|
||||||
if (arg_count >= 1 && !wcscmp(argv[w.woptind], L"choice")) {
|
|
||||||
if (arg_count == 1) {
|
|
||||||
streams.err.append_format(L"%ls: nothing to choose from\n", argv[0]);
|
|
||||||
return STATUS_INVALID_ARGS;
|
|
||||||
}
|
|
||||||
choice = true;
|
|
||||||
start = 1;
|
|
||||||
step = 1;
|
|
||||||
end = arg_count - 1;
|
|
||||||
} else {
|
|
||||||
bool parse_error = false;
|
|
||||||
auto parse_ll = [&](const wchar_t *str) {
|
|
||||||
long long ll = fish_wcstoll(str);
|
|
||||||
if (errno) {
|
|
||||||
streams.err.append_format(L"%ls: %ls is not a valid integer\n", argv[0], str);
|
|
||||||
parse_error = true;
|
|
||||||
}
|
|
||||||
return ll;
|
|
||||||
};
|
|
||||||
auto parse_ull = [&](const wchar_t *str) {
|
|
||||||
unsigned long long ull = fish_wcstoull(str);
|
|
||||||
if (errno) {
|
|
||||||
streams.err.append_format(L"%ls: %ls is not a valid integer\n", argv[0], str);
|
|
||||||
parse_error = true;
|
|
||||||
}
|
|
||||||
return ull;
|
|
||||||
};
|
|
||||||
if (arg_count == 0) {
|
|
||||||
start = 0;
|
|
||||||
end = 32767;
|
|
||||||
step = 1;
|
|
||||||
} else if (arg_count == 1) {
|
|
||||||
long long seed = parse_ll(argv[w.woptind]);
|
|
||||||
if (parse_error) return STATUS_INVALID_ARGS;
|
|
||||||
engine.seed(static_cast<uint32_t>(seed));
|
|
||||||
return STATUS_CMD_OK;
|
|
||||||
} else if (arg_count == 2) {
|
|
||||||
start = parse_ll(argv[w.woptind]);
|
|
||||||
step = 1;
|
|
||||||
end = parse_ll(argv[w.woptind + 1]);
|
|
||||||
} else if (arg_count == 3) {
|
|
||||||
start = parse_ll(argv[w.woptind]);
|
|
||||||
step = parse_ull(argv[w.woptind + 1]);
|
|
||||||
end = parse_ll(argv[w.woptind + 2]);
|
|
||||||
} else {
|
|
||||||
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]);
|
|
||||||
return STATUS_INVALID_ARGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parse_error) {
|
|
||||||
return STATUS_INVALID_ARGS;
|
|
||||||
} else if (start >= end) {
|
|
||||||
streams.err.append_format(L"%ls: END must be greater than START\n", argv[0]);
|
|
||||||
return STATUS_INVALID_ARGS;
|
|
||||||
} else if (step == 0) {
|
|
||||||
streams.err.append_format(L"%ls: STEP must be a positive integer\n", argv[0]);
|
|
||||||
return STATUS_INVALID_ARGS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only for negative argument
|
|
||||||
auto safe_abs = [](long long ll) -> unsigned long long {
|
|
||||||
return -static_cast<unsigned long long>(ll);
|
|
||||||
};
|
|
||||||
long long real_end;
|
|
||||||
if (start >= 0 || end < 0) {
|
|
||||||
// 0 <= start <= end
|
|
||||||
long long diff = end - start;
|
|
||||||
// 0 <= diff <= LL_MAX
|
|
||||||
real_end = start + static_cast<long long>(diff / step);
|
|
||||||
} else {
|
|
||||||
// start < 0 <= end
|
|
||||||
unsigned long long abs_start = safe_abs(start);
|
|
||||||
unsigned long long diff = (end + abs_start);
|
|
||||||
real_end = diff / step - abs_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!choice && start == real_end) {
|
|
||||||
streams.err.append_format(L"%ls: range contains only one possible value\n", argv[0]);
|
|
||||||
return STATUS_INVALID_ARGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uniform_int_distribution<long long> dist(start, real_end);
|
|
||||||
long long random = dist(engine);
|
|
||||||
long long result;
|
|
||||||
if (start >= 0) {
|
|
||||||
// 0 <= start <= random <= end
|
|
||||||
long long diff = random - start;
|
|
||||||
// 0 < step * diff <= end - start <= LL_MAX
|
|
||||||
result = start + static_cast<long long>(diff * step);
|
|
||||||
} else if (random < 0) {
|
|
||||||
// start <= random < 0
|
|
||||||
long long diff = random - start;
|
|
||||||
result = diff * step - safe_abs(start);
|
|
||||||
} else {
|
|
||||||
// start < 0 <= random
|
|
||||||
unsigned long long abs_start = safe_abs(start);
|
|
||||||
unsigned long long diff = (random + abs_start);
|
|
||||||
result = diff * step - abs_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (choice) {
|
|
||||||
streams.out.append_format(L"%ls\n", argv[w.woptind + result]);
|
|
||||||
} else {
|
|
||||||
streams.out.append_format(L"%lld\n", result);
|
|
||||||
}
|
|
||||||
return STATUS_CMD_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The exit builtin. Calls reader_exit to exit and returns the value specified.
|
/// The exit builtin. Calls reader_exit to exit and returns the value specified.
|
||||||
static int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
static int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
int argc = builtin_count_args(argv);
|
int argc = builtin_count_args(argv);
|
||||||
|
|
191
src/builtin_random.cpp
Normal file
191
src/builtin_random.cpp
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
// Implementation of the random builtin.
|
||||||
|
#include "config.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include "builtin.h"
|
||||||
|
#include "builtin_random.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "fallback.h" // IWYU pragma: keep
|
||||||
|
#include "io.h"
|
||||||
|
#include "wgetopt.h"
|
||||||
|
#include "wutil.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
struct random_opts {
|
||||||
|
bool print_help = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const wchar_t *short_options = L"h";
|
||||||
|
static const struct woption long_options[] = {{L"help", no_argument, NULL, 'h'},
|
||||||
|
{NULL, 0, NULL, 0}};
|
||||||
|
|
||||||
|
static int parse_random_opts(struct random_opts *opts, int *optind, //!OCLINT(high ncss method)
|
||||||
|
int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) {
|
||||||
|
wchar_t *cmd = argv[0];
|
||||||
|
int opt;
|
||||||
|
wgetopter_t w;
|
||||||
|
while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
|
||||||
|
switch (opt) { //!OCLINT(too few branches)
|
||||||
|
case 'h': {
|
||||||
|
opts->print_help = true;
|
||||||
|
return STATUS_CMD_OK;
|
||||||
|
}
|
||||||
|
case '?': {
|
||||||
|
builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
DIE("unexpected retval from wgetopt_long");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*optind = w.woptind;
|
||||||
|
return STATUS_CMD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The random builtin generates random numbers.
|
||||||
|
int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||||
|
wchar_t *cmd = argv[0];
|
||||||
|
int argc = builtin_count_args(argv);
|
||||||
|
struct random_opts opts;
|
||||||
|
|
||||||
|
int optind;
|
||||||
|
int retval = parse_random_opts(&opts, &optind, argc, argv, parser, streams);
|
||||||
|
if (retval != STATUS_CMD_OK) return retval;
|
||||||
|
|
||||||
|
if (opts.print_help) {
|
||||||
|
builtin_print_help(parser, streams, cmd, streams.out);
|
||||||
|
return STATUS_CMD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool seeded = false;
|
||||||
|
static std::minstd_rand engine;
|
||||||
|
if (!seeded) {
|
||||||
|
// seed engine with 2*32 bits of random data
|
||||||
|
// for the 64 bits of internal state of minstd_rand
|
||||||
|
std::random_device rd;
|
||||||
|
std::seed_seq seed{rd(), rd()};
|
||||||
|
engine.seed(seed);
|
||||||
|
seeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arg_count = argc - optind;
|
||||||
|
long long start, end;
|
||||||
|
unsigned long long step;
|
||||||
|
bool choice = false;
|
||||||
|
if (arg_count >= 1 && !wcscmp(argv[optind], L"choice")) {
|
||||||
|
if (arg_count == 1) {
|
||||||
|
streams.err.append_format(L"%ls: nothing to choose from\n", cmd);
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
choice = true;
|
||||||
|
start = 1;
|
||||||
|
step = 1;
|
||||||
|
end = arg_count - 1;
|
||||||
|
} else {
|
||||||
|
bool parse_error = false;
|
||||||
|
auto parse_ll = [&](const wchar_t *str) {
|
||||||
|
long long ll = fish_wcstoll(str);
|
||||||
|
if (errno) {
|
||||||
|
streams.err.append_format(L"%ls: %ls is not a valid integer\n", cmd, str);
|
||||||
|
parse_error = true;
|
||||||
|
}
|
||||||
|
return ll;
|
||||||
|
};
|
||||||
|
auto parse_ull = [&](const wchar_t *str) {
|
||||||
|
unsigned long long ull = fish_wcstoull(str);
|
||||||
|
if (errno) {
|
||||||
|
streams.err.append_format(L"%ls: %ls is not a valid integer\n", cmd, str);
|
||||||
|
parse_error = true;
|
||||||
|
}
|
||||||
|
return ull;
|
||||||
|
};
|
||||||
|
if (arg_count == 0) {
|
||||||
|
start = 0;
|
||||||
|
end = 32767;
|
||||||
|
step = 1;
|
||||||
|
} else if (arg_count == 1) {
|
||||||
|
long long seed = parse_ll(argv[optind]);
|
||||||
|
if (parse_error) return STATUS_INVALID_ARGS;
|
||||||
|
engine.seed(static_cast<uint32_t>(seed));
|
||||||
|
return STATUS_CMD_OK;
|
||||||
|
} else if (arg_count == 2) {
|
||||||
|
start = parse_ll(argv[optind]);
|
||||||
|
step = 1;
|
||||||
|
end = parse_ll(argv[optind + 1]);
|
||||||
|
} else if (arg_count == 3) {
|
||||||
|
start = parse_ll(argv[optind]);
|
||||||
|
step = parse_ull(argv[optind + 1]);
|
||||||
|
end = parse_ll(argv[optind + 2]);
|
||||||
|
} else {
|
||||||
|
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parse_error) {
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
} else if (start >= end) {
|
||||||
|
streams.err.append_format(L"%ls: END must be greater than START\n", cmd);
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
} else if (step == 0) {
|
||||||
|
streams.err.append_format(L"%ls: STEP must be a positive integer\n", cmd);
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// only for negative argument
|
||||||
|
auto safe_abs = [](long long ll) -> unsigned long long {
|
||||||
|
return -static_cast<unsigned long long>(ll);
|
||||||
|
};
|
||||||
|
long long real_end;
|
||||||
|
if (start >= 0 || end < 0) {
|
||||||
|
// 0 <= start <= end
|
||||||
|
long long diff = end - start;
|
||||||
|
// 0 <= diff <= LL_MAX
|
||||||
|
real_end = start + static_cast<long long>(diff / step);
|
||||||
|
} else {
|
||||||
|
// start < 0 <= end
|
||||||
|
unsigned long long abs_start = safe_abs(start);
|
||||||
|
unsigned long long diff = (end + abs_start);
|
||||||
|
real_end = diff / step - abs_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!choice && start == real_end) {
|
||||||
|
streams.err.append_format(L"%ls: range contains only one possible value\n", cmd);
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uniform_int_distribution<long long> dist(start, real_end);
|
||||||
|
long long random = dist(engine);
|
||||||
|
long long result;
|
||||||
|
if (start >= 0) {
|
||||||
|
// 0 <= start <= random <= end
|
||||||
|
long long diff = random - start;
|
||||||
|
// 0 < step * diff <= end - start <= LL_MAX
|
||||||
|
result = start + static_cast<long long>(diff * step);
|
||||||
|
} else if (random < 0) {
|
||||||
|
// start <= random < 0
|
||||||
|
long long diff = random - start;
|
||||||
|
result = diff * step - safe_abs(start);
|
||||||
|
} else {
|
||||||
|
// start < 0 <= random
|
||||||
|
unsigned long long abs_start = safe_abs(start);
|
||||||
|
unsigned long long diff = (random + abs_start);
|
||||||
|
result = diff * step - abs_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choice) {
|
||||||
|
streams.out.append_format(L"%ls\n", argv[optind + result]);
|
||||||
|
} else {
|
||||||
|
streams.out.append_format(L"%lld\n", result);
|
||||||
|
}
|
||||||
|
return STATUS_CMD_OK;
|
||||||
|
}
|
9
src/builtin_random.h
Normal file
9
src/builtin_random.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// Prototypes for executing builtin_random function.
|
||||||
|
#ifndef FISH_BUILTIN_RANDOM_H
|
||||||
|
#define FISH_BUILTIN_RANDOM_H
|
||||||
|
|
||||||
|
class parser_t;
|
||||||
|
struct io_streams_t;
|
||||||
|
|
||||||
|
int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv);
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user