2018-02-24 03:24:50 +01:00
|
|
|
/**
|
|
|
|
Buridan's Donkey, Asino.
|
|
|
|
Copyright: Francesco Mecca
|
|
|
|
License: GPLv3
|
|
|
|
Author: Francesco Mecca
|
|
|
|
*/
|
|
|
|
module asino;
|
|
|
|
|
2017-07-17 13:03:46 +02:00
|
|
|
import std.stdio;
|
|
|
|
import std.random;
|
|
|
|
import std.getopt;
|
2018-02-24 03:24:50 +01:00
|
|
|
import std.file;
|
|
|
|
import std.conv;
|
2018-02-24 05:30:45 +01:00
|
|
|
import std.array;
|
|
|
|
import std.algorithm;
|
|
|
|
|
|
|
|
extern(C)
|
|
|
|
{
|
|
|
|
struct pollfd { int fd; short events; short revents; }
|
|
|
|
int poll(pollfd *fds, int nfds, int timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
string versionSt = "...a man, being just as hungry as thirsty,
|
|
|
|
and placed in between food and drink,
|
2018-02-24 05:36:30 +01:00
|
|
|
must necessarily remain where he is and starve to death
|
2018-02-24 05:30:45 +01:00
|
|
|
|
|
|
|
Aristole";
|
|
|
|
|
2017-07-17 13:03:46 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
main (string[] args)
|
|
|
|
{
|
2018-02-24 05:30:45 +01:00
|
|
|
bool num, v;
|
2018-02-24 03:24:50 +01:00
|
|
|
string engine = "mt";
|
2018-02-24 05:30:45 +01:00
|
|
|
string div;
|
2018-02-24 03:24:50 +01:00
|
|
|
auto cliOpts = getopt(
|
2017-07-17 13:03:46 +02:00
|
|
|
args,
|
2018-02-24 03:24:50 +01:00
|
|
|
"numbers|n", "enable number output on screen", &num,
|
2018-02-24 05:30:45 +01:00
|
|
|
"divider|d", "divide the arguments using a different divider", &div,
|
|
|
|
"version|v", "show version and exit", &v,
|
2018-02-24 03:24:50 +01:00
|
|
|
"engine|e", "Choose the RNG between \"mt\" (Mersenne-Twister, default), \"x\" (xorshift),
|
|
|
|
\"dr\" (/dev/random), \"du\" (/dev/urandom)", &engine
|
|
|
|
);
|
|
|
|
|
2018-02-24 05:30:45 +01:00
|
|
|
if(cliOpts.helpWanted){
|
|
|
|
defaultGetoptPrinter("Buridan's Donkey\nSort a list of strings randomly", cliOpts.options);
|
2018-02-24 03:24:50 +01:00
|
|
|
return;
|
2018-02-24 05:30:45 +01:00
|
|
|
} else if(v){
|
|
|
|
writeln(versionSt);
|
2018-02-24 03:24:50 +01:00
|
|
|
}
|
2017-07-17 13:03:46 +02:00
|
|
|
|
2018-02-24 05:30:45 +01:00
|
|
|
string[] toProcess = void;
|
|
|
|
if(isaTTY()){
|
|
|
|
// read stdin, ignore cli args
|
2018-07-04 14:42:59 +02:00
|
|
|
toProcess = to!(string[])(File("/dev/stdin").byLineCopy.array());
|
2018-02-24 05:30:45 +01:00
|
|
|
} else {
|
|
|
|
toProcess = args[1 .. $]; // remove program name
|
|
|
|
}
|
|
|
|
|
|
|
|
auto res = toProcess.divide(div).shuffle(engine);
|
2017-07-17 13:03:46 +02:00
|
|
|
|
2018-02-24 05:30:45 +01:00
|
|
|
foreach (i, arg; res) {
|
2018-02-24 03:24:50 +01:00
|
|
|
if (!num) writeln(arg);
|
2018-02-24 05:36:30 +01:00
|
|
|
else writefln("%s: %s", i + 1, arg);
|
2017-07-17 13:03:46 +02:00
|
|
|
}
|
2018-02-24 03:24:50 +01:00
|
|
|
}
|
|
|
|
|
2018-02-24 05:30:45 +01:00
|
|
|
string[] divide(string[] args, string div)
|
|
|
|
{
|
|
|
|
if (div == "") return args;
|
|
|
|
else return to!(string[])(args.join.splitter(div).array);
|
|
|
|
}
|
|
|
|
|
|
|
|
string[] shuffle(string[] args, string t)
|
2018-02-24 03:24:50 +01:00
|
|
|
{
|
|
|
|
if(t == "mt"){
|
|
|
|
Mt19937 gen;
|
|
|
|
gen.seed(unpredictableSeed);
|
|
|
|
args.randomShuffle(gen);
|
|
|
|
} else if (t == "x"){
|
|
|
|
Xorshift32 gen;
|
|
|
|
gen.seed(unpredictableSeed);
|
|
|
|
args.randomShuffle(gen);
|
|
|
|
} else if (t == "du"){
|
|
|
|
auto gen = DevRandomGen!"/dev/urandom"();
|
|
|
|
args.randomShuffle(gen);
|
|
|
|
} else if (t == "dr"){
|
|
|
|
auto gen = DevRandomGen!"/dev/random"();
|
|
|
|
args.randomShuffle(gen);
|
|
|
|
} else {
|
|
|
|
throw new Exception("Wrong arguments");
|
|
|
|
}
|
2018-02-24 05:30:45 +01:00
|
|
|
return args;
|
2018-02-24 03:24:50 +01:00
|
|
|
}
|
|
|
|
|
2017-07-17 13:03:46 +02:00
|
|
|
|
2018-02-24 03:24:50 +01:00
|
|
|
template DevRandomGen(string gen)
|
|
|
|
if (gen == "/dev/random" || gen == "/dev/urandom")
|
|
|
|
{
|
|
|
|
struct DevRandomGen
|
|
|
|
{
|
|
|
|
|
|
|
|
alias UIntType = uint;
|
|
|
|
public:
|
|
|
|
enum bool isUniformRandom = true;
|
|
|
|
enum empty = false;
|
|
|
|
/// Smallest generated value.
|
|
|
|
enum UIntType min = 0;
|
|
|
|
/// Largest generated value.
|
|
|
|
enum UIntType max = ubyte.max;
|
|
|
|
string src = gen;
|
|
|
|
|
|
|
|
void seed(UIntType x0) @safe pure nothrow @nogc {}
|
|
|
|
void popFront() @safe pure nothrow @nogc {}
|
|
|
|
|
2018-02-24 05:30:45 +01:00
|
|
|
@property
|
|
|
|
UIntType front() const { return (cast(ubyte[])(src.read(ubyte.sizeof)))[0]; }
|
2018-02-24 03:24:50 +01:00
|
|
|
|
|
|
|
@property
|
2018-02-24 05:30:45 +01:00
|
|
|
typeof(this) save() @safe pure nothrow @nogc { return this; }
|
2018-02-24 03:24:50 +01:00
|
|
|
}
|
2017-07-17 13:03:46 +02:00
|
|
|
}
|
2018-02-24 05:30:45 +01:00
|
|
|
|
|
|
|
bool isaTTY()
|
|
|
|
{
|
|
|
|
pollfd fds;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
fds.fd = 0;
|
|
|
|
fds.events = 0;
|
|
|
|
ret = poll(&fds, 1, 0);
|
|
|
|
return ret > 0;
|
|
|
|
}
|