From 6ca844da053f979d169a6de01167dfa7a02b4696 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 31 Mar 2023 13:55:55 -0500 Subject: [PATCH] Add shuf. --- toys/other/shuf.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 toys/other/shuf.c diff --git a/toys/other/shuf.c b/toys/other/shuf.c new file mode 100644 index 00000000..fe8230f1 --- /dev/null +++ b/toys/other/shuf.c @@ -0,0 +1,63 @@ +/* shuf.c - Output lines in random order. + * + * Copyright 2023 Rob Landley + * + * See https://man7.org/linux/man-pages/man1/shuf.1.html + +USE_SHUF(NEWTOY(shuf, "zen#<0", TOYFLAG_USR|TOYFLAG_BIN)) + +config SHUF + bool "shuf" + default y + help + usage: shuf [-ze] [-n COUNT] [FILE...] + + Write lines of input to output in random order. + + -z Input/output lines are NUL terminated. + -n Stop after COUNT many output lines. + -e Echo mode: arguments are inputs to shuffle, not files to read. +*/ + +#define FOR_shuf +#include "toys.h" + +GLOBALS( + long n; + + char **lines; + long count; +) + +static void do_shuf_line(char **pline, long len) +{ + if (!pline) return; + if (!(TT.count&255)) + TT.lines = xrealloc(TT.lines, sizeof(void *)*(TT.count+256)); + TT.lines[TT.count++] = *pline; // TODO: repack? + *pline = 0; +} + +static void do_shuf(int fd, char *name) +{ + do_lines(fd, '\n'*!FLAG(z), do_shuf_line); +} + +void shuf_main(void) +{ + if (FLAG(e)) { + TT.lines = toys.optargs; + TT.count = toys.optc; + } else loopfiles(toys.optargs, do_shuf); + + if (!FLAG(n) || TT.n>TT.count) TT.n = TT.count; + + srandom(millitime()); + while (TT.n--) { + long ll = random()%TT.count; + writeall(1, TT.lines[ll], strlen(TT.lines[ll])+FLAG(z)); + if (!FLAG(e)) free(TT.lines[ll]); + else if (!FLAG(z)) writeall(1, "\n", 1); + TT.lines[ll] = TT.lines[--TT.count]; + } +} -- 2.39.2