add another one useful for .profile
[shellsnippets/shellsnippets.git] / mksh / _remfornd
1 #!/usr/bin/env mksh
2 # From MirOS: contrib/code/Snippets/shuffle,v 1.7 2012/10/19 18:59:39 tg Exp $
3 #-
4 # Copyright © 2006, 2010, 2011, 2012, 2015, 2017
5 #       mirabilos <m@mirbsd.org>
6 #
7 # Provided that these terms and disclaimer and all copyright notices
8 # are retained or reproduced in an accompanying document, permission
9 # is granted to deal in this work without restriction, including un‐
10 # limited rights to use, publicly perform, distribute, sell, modify,
11 # merge, give away, or sublicence.
12 #
13 # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
14 # the utmost extent permitted by applicable law, neither express nor
15 # implied; without malicious intent or gross negligence. In no event
16 # may a licensor, author or contributor be held liable for indirect,
17 # direct, other damage, loss, or other issues arising in any way out
18 # of dealing in the work, even if advised of the possibility of such
19 # damage or existence of a defect, except proven that it results out
20 # of said person’s immediate fault when using the work as intended.
21 #-
22 # Hack for _remfor shuffling the input
23
24 ulimit -c 0
25
26 local _i _fm=$2 _h=$1
27 shift; shift
28
29 [[ $_fm = *'*' ]] || _fm=${_fm@Q}
30 set -A files
31 integer nfiles=0
32
33 trap "" INT
34 ssh -n "$_h" find "$_fm" -type f -print0 |&
35 while IFS= read -p -r -d "" _i; do
36         files[nfiles++]=$_i
37 done
38
39 # arc4random(3) in Pure mksh™
40 set -A seedbuf -- $(dd if=/dev/arandom bs=257 count=1 2>&- | \
41     hexdump -ve '1/1 "0x%02X "')
42 set -A rs_S
43 typeset -i rs_S rs_i=-1 rs_j=0 n
44 while (( ++rs_i < 256 )); do
45         (( rs_S[rs_i] = rs_i ))
46 done
47 rs_i=-1
48 while (( ++rs_i < 256 )); do
49         (( n = rs_S[rs_i] ))
50         (( rs_j = (rs_j + n + seedbuf[rs_i]) & 0xFF ))
51         (( rs_S[rs_i] = rs_S[rs_j] ))
52         (( rs_S[rs_j] = n ))
53 done
54 rs_i=0
55 rs_j=0
56 typeset -i rs_out
57 function arcfour_byte {
58         typeset -i si sj
59
60         (( rs_i = (rs_i + 1) & 0xFF ))
61         (( si = rs_S[rs_i] ))
62         (( rs_j = (rs_j + si) & 0xFF ))
63         (( sj = rs_S[rs_j] ))
64         (( rs_S[rs_i] = sj ))
65         (( rs_S[rs_j] = si ))
66         (( rs_out = rs_S[(si + sj) & 0xFF] ))
67 }
68 (( n = 256 * 12 + seedbuf[256] + (RANDOM & 0xFF) ))
69 while (( n-- )); do
70         arcfour_byte
71 done
72 (( n = rs_out ))
73 while (( n-- )); do
74         arcfour_byte
75 done
76
77 typeset -Uui16 -Z11 arc4random_rv
78 function arc4random {
79         # apply uncertainty
80         arcfour_byte
81         (( rs_out & 1 )) && arcfour_byte
82         # read four octets into result dword
83         arcfour_byte
84         (( arc4random_rv = rs_out ))
85         arcfour_byte
86         (( arc4random_rv |= rs_out << 8 ))
87         arcfour_byte
88         (( arc4random_rv |= rs_out << 16 ))
89         arcfour_byte
90         (( arc4random_rv |= rs_out << 24 ))
91 }
92
93 # arc4random_uniform(3) in Pure mksh™
94 function arc4random_uniform {
95         # Derived from code written by Damien Miller <djm@openbsd.org>
96         # published under the ISC licence, with simplifications by
97         # Jinmei Tatuya. Written in mksh by Thorsten Glaser.
98         #-
99         # Calculate a uniformly distributed random number less than
100         # upper_bound avoiding “modulo bias”.
101         # Uniformity is achieved by generating new random numbers
102         # until the one returned is outside the range
103         # [0, 2^32 % upper_bound[. This guarantees the selected
104         # random number will be inside the range
105         # [2^32 % upper_bound, 2^32[ which maps back to
106         # [0, upper_bound[ after reduction modulo upper_bound.
107         #-
108         typeset -Ui upper_bound=$1 min
109
110         if (( upper_bound < 2 )); then
111                 arc4random_rv=0
112                 return
113         fi
114
115         # calculate (2^32 % upper_bound) avoiding 64-bit math
116         # if upper_bound > 2^31: 2^32 - upper_bound (only one
117         # “value area”); otherwise (x <= 2^31) use the fact
118         # that ((2^32 - x) % x) == (2^32 % x)
119         ((# min = upper_bound > 0x80000000 ? 1 + ~upper_bound :
120             (0xFFFFFFFF - upper_bound + 1) % upper_bound ))
121
122         # This could theoretically loop forever but each retry has
123         # p > 0.5 (worst case, usually far better) of selecting a
124         # number inside the range we need, so it should rarely need
125         # to re-roll (at all).
126         while :; do
127                 arc4random
128                 ((# arc4random_rv >= min )) && break
129         done
130
131         ((# arc4random_rv %= upper_bound ))
132 }
133
134
135 (( ++nfiles ))
136 while (( --nfiles )); do
137         arc4random_uniform $nfiles
138         _i=${files[arc4random_rv]}
139         print -r "◖${_i}◗"
140         ssh -n "$_h" cat "${_i@Q}" | "$@"
141         unset files[arc4random_rv]
142         set -A files -- "${files[@]}"
143 done