1 /* shuf.c - Output lines in random order.
2 *
3 * Copyright 2023 Rob Landley <[email protected]>
4 *
5 * See https://man7.org/linux/man-pages/man1/shuf.1.html
6
7 USE_SHUF(NEWTOY(shuf, "zen#<0", TOYFLAG_USR|TOYFLAG_BIN))
8
9 config SHUF
10 bool "shuf"
11 default y
12 help
13 usage: shuf [-ze] [-n COUNT] [FILE...]
14
15 Write lines of input to output in random order.
16
17 -z Input/output lines are NUL terminated.
18 -n Stop after COUNT many output lines.
19 -e Echo mode: arguments are inputs to shuffle, not files to read.
20 */
21
22 #define FOR_shuf
23 #include "toys.h"
24
GLOBALS(long n;char ** lines;long count;)25 GLOBALS(
26 long n;
27
28 char **lines;
29 long count;
30 )
31
32 static void do_shuf_line(char **pline, long len)
33 {
34 if (!pline) return;
35 if (!(TT.count&255))
36 TT.lines = xrealloc(TT.lines, sizeof(void *)*(TT.count+256));
37 TT.lines[TT.count++] = *pline; // TODO: repack?
38 *pline = 0;
39 }
40
do_shuf(int fd,char * name)41 static void do_shuf(int fd, char *name)
42 {
43 do_lines(fd, '\n'*!FLAG(z), do_shuf_line);
44 }
45
shuf_main(void)46 void shuf_main(void)
47 {
48 if (FLAG(e)) {
49 TT.lines = toys.optargs;
50 TT.count = toys.optc;
51 } else loopfiles(toys.optargs, do_shuf);
52
53 if (!FLAG(n) || TT.n>TT.count) TT.n = TT.count;
54
55 srandom(millitime());
56 while (TT.n--) {
57 long ll = random()%TT.count;
58 writeall(1, TT.lines[ll], strlen(TT.lines[ll])+FLAG(z));
59 if (!FLAG(e)) free(TT.lines[ll]);
60 else if (!FLAG(z)) writeall(1, "\n", 1);
61 TT.lines[ll] = TT.lines[--TT.count];
62 }
63 }
64