---
Makefile | 1 +
README | 1 +
shuf.1 | 26 +++++++++++
shuf.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 177 insertions(+)
create mode 100644 shuf.1
create mode 100644 shuf.c
diff --git a/Makefile b/Makefile
index 6b2bfdf..e407663 100644
--- a/Makefile
+++ b/Makefile
_AT_@ -149,6 +149,7 @@ BIN =\
sha512sum\
sha512-224sum\
sha512-256sum\
+ shuf\
sleep\
sort\
split\
diff --git a/README b/README
index d60d8fc..e752a09 100644
--- a/README
+++ b/README
_AT_@ -78,6 +78,7 @@ The following tools are implemented:
0=*|x sha512sum .
0=* x sha512-224sum .
0=* x sha512-256sum .
+0=* x shuf (-e, -i, -n, -o, -z)
0=*|o sleep .
0#*|o sort .
0=*|o split .
diff --git a/shuf.1 b/shuf.1
new file mode 100644
index 0000000..ce0dcd0
--- /dev/null
+++ b/shuf.1
_AT_@ -0,0 +1,26 @@
+.Dd 2016-03-26
+.Dt SHUF 1
+.Os sbase
+.Sh NAME
+.Nm shuf
+.Nd shuffle the lines in a file
+.Sh SYNOPSIS
+.Nm
+.Op Fl r
+.Op Fl s Ar source
+.Op Ar file
+.Sh DESCRIPTION
+.Nm
+reads each line from
+.Ar file
+and prints its line in random order.
+.Nm
+reads from stdin.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl r
+Output random lines ad infinitum.
+.It Fl s Ar source
+Get random bytes from
+.Ar source .
+.El
diff --git a/shuf.c b/shuf.c
new file mode 100644
index 0000000..a325bb2
--- /dev/null
+++ b/shuf.c
_AT_@ -0,0 +1,149 @@
+/* See LICENSE file for copyright and license details. */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "text.h"
+#include "util.h"
+
+static int source = -1;
+static char *sflag = 0;
+static int (*random_byte)(void);
+
+static void
+usage(void)
+{
+ eprintf("usage: %s [-r] [-s source] [file]\n", argv0);
+}
+
+static int
+random_byte_file(void)
+{
+ unsigned char r;
+ ssize_t n = read(source, &r, 1);
+ if (n < 0)
+ eprintf("read %s:", sflag);
+ if (!n)
+ eprintf("read %s: end of file reached\n");
+ return r;
+}
+
+static int
+random_byte_libc(void)
+{
+ double r;
+ r = rand();
+ r /= (double)RAND_MAX + 1;
+ r *= 256;
+ return (int)r;
+}
+
+static size_t
+random_int(size_t max)
+{
+ size_t n = max;
+ size_t r = 0;
+ size_t mask = max;
+ int s = 1;
+
+ while (((mask + 1) & ~mask) != (mask + 1))
+ mask |= mask >> s++;
+
+ do {
+ while (n) {
+ n >>= 8;
+ r <<= 8;
+ r |= random_byte();
+ }
+ r &= mask;
+ } while (r > max);
+
+ return r;
+}
+
+static void
+shuf(FILE *fp, int repeat)
+{
+ struct linebuf lines = EMPTY_LINEBUF;
+ struct line line;
+ size_t i, j;
+
+ getlines(fp, &lines);
+
+ if (source < 0) {
+ srand((intptr_t)(lines.lines) | time(NULL));
+ random_byte = random_byte_libc;
+ } else {
+ random_byte = random_byte_file;
+ }
+
+ if (repeat) {
+ if (!lines.nlines)
+ eprintf("no lines to repeat\n");
+ for (;;) {
+ i = random_int(lines.nlines - 1);
+ line = lines.lines[i];
+ fwrite(line.data, 1, line.len, stdout);
+ }
+ }
+
+ for (i = lines.nlines; i--;) {
+ j = random_int(i);
+ line = lines.lines[i];
+ lines.lines[i] = lines.lines[j];
+ lines.lines[j] = line;
+ }
+ for (i = lines.nlines; i--;) {
+ line = lines.lines[i];
+ fwrite(line.data, 1, line.len, stdout);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fp;
+ int rflag = 0;
+ int ret = 0;
+
+ ARGBEGIN {
+ case 'r':
+ rflag = 1;
+ break;
+ case 's':
+ if (source >= 0)
+ close(source);
+ source = open(sflag = EARGF(usage()), O_RDONLY);
+ if (source < 0)
+ eprintf("open %s:", sflag);
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if (argc > 1)
+ usage();
+
+ if (!argc) {
+ shuf(stdin, rflag);
+ } else {
+ if (!strcmp(*argv, "-")) {
+ *argv = "<stdin>";
+ fp = stdin;
+ } else if (!(fp = fopen(*argv, "r"))) {
+ eprintf("fopen %s:", *argv);
+ }
+ shuf(fp, rflag);
+ if (fp != stdin && fshut(fp, *argv))
+ ret = 1;
+ }
+
+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
+ if (source >= 0)
+ close(source);
+
+ return ret;
+}
--
2.7.3
Received on Sat Mar 26 2016 - 13:50:47 CET
This archive was generated by hypermail 2.3.0 : Sat Mar 26 2016 - 14:00:18 CET