mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-02-12 02:12:06 +02:00
New file, introduced for shuf, sort -R, and/or shred.
This commit is contained in:
108
lib/memxfrm.c
Normal file
108
lib/memxfrm.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/* Locale-specific memory transformation
|
||||
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Written by Paul Eggert <eggert@cs.ucla.edu>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "memxfrm.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Store into DEST (of size DESTSIZE) the text in SRC (of size SRCSIZE)
|
||||
transformed so that the result of memcmp on two transformed texts
|
||||
(with ties going to the longer text) is the same as the result of
|
||||
memcoll on the two texts before their transformation. Perhaps
|
||||
temporarily modify the byte after SRC, but restore its original
|
||||
contents before returning.
|
||||
|
||||
Return the size of the resulting text, or an indeterminate value if
|
||||
there is an error. Set errno to an error number if there is an
|
||||
error, and to zero otherwise. DEST contains an indeterminate value
|
||||
if there is an error or if the resulting size is greater than
|
||||
DESTSIZE. */
|
||||
|
||||
size_t
|
||||
memxfrm (char *restrict dest, size_t destsize,
|
||||
char *restrict src, size_t srcsize)
|
||||
{
|
||||
#if HAVE_STRXFRM
|
||||
|
||||
size_t di = 0;
|
||||
size_t si = 0;
|
||||
size_t result = 0;
|
||||
|
||||
char ch = src[srcsize];
|
||||
src[srcsize] = '\0';
|
||||
|
||||
while (si < srcsize)
|
||||
{
|
||||
size_t slen = strlen (src + si);
|
||||
|
||||
size_t result0 = result;
|
||||
errno = 0;
|
||||
result += strxfrm (dest + di, src + si, destsize - di) + 1;
|
||||
if (errno != 0)
|
||||
break;
|
||||
if (result <= result0)
|
||||
{
|
||||
errno = ERANGE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == destsize + 1 && si + slen == srcsize)
|
||||
{
|
||||
/* The destination is exactly the right size, but strxfrm wants
|
||||
room for a trailing null. Work around the problem with a
|
||||
temporary buffer. */
|
||||
size_t bufsize = destsize - di + 1;
|
||||
char stackbuf[4000];
|
||||
char *buf = stackbuf;
|
||||
if (sizeof stackbuf < bufsize)
|
||||
{
|
||||
buf = malloc (bufsize);
|
||||
if (! buf)
|
||||
break;
|
||||
}
|
||||
strxfrm (buf, src + si, bufsize);
|
||||
memcpy (dest + di, buf, destsize - di);
|
||||
if (sizeof stackbuf < bufsize)
|
||||
free (buf);
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
di = (result < destsize ? result : destsize);
|
||||
si += slen + 1;
|
||||
}
|
||||
|
||||
src[srcsize] = ch;
|
||||
return result - (si != srcsize);
|
||||
|
||||
#else
|
||||
|
||||
if (srcsize < destsize)
|
||||
memcpy (dest, src, srcsize);
|
||||
errno = 0;
|
||||
return srcsize;
|
||||
|
||||
#endif
|
||||
}
|
||||
2
lib/memxfrm.h
Normal file
2
lib/memxfrm.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#include <stddef.h>
|
||||
size_t memxfrm (char *restrict, size_t, char *restrict, size_t);
|
||||
300
lib/rand-isaac.c
Normal file
300
lib/rand-isaac.c
Normal file
@@ -0,0 +1,300 @@
|
||||
/* Bob Jenkins's cryptographic random number generator, ISAAC.
|
||||
|
||||
Copyright (C) 1999-2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 1997, 1998, 1999 Colin Plumb.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Written by Colin Plumb. */
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------
|
||||
* We need a source of random numbers for some data.
|
||||
* Cryptographically secure is desirable, but it's not life-or-death
|
||||
* so I can be a little bit experimental in the choice of RNGs here.
|
||||
*
|
||||
* This generator is based somewhat on RC4, but has analysis
|
||||
* <http://burtleburtle.net/bob/rand/isaacafa.html>
|
||||
* pointing to it actually being better. I like it because it's nice
|
||||
* and fast, and because the author did good work analyzing it.
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rand-isaac.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "gethrxtime.h"
|
||||
|
||||
|
||||
/* This index operation is more efficient on many processors */
|
||||
#define ind(mm, x) \
|
||||
(* (uint32_t *) ((char *) (mm) \
|
||||
+ ((x) & (ISAAC_WORDS - 1) * sizeof (uint32_t))))
|
||||
|
||||
/*
|
||||
* The central step. This uses two temporaries, x and y. mm is the
|
||||
* whole state array, while m is a pointer to the current word. off is
|
||||
* the offset from m to the word ISAAC_WORDS/2 words away in the mm array,
|
||||
* i.e. +/- ISAAC_WORDS/2.
|
||||
*/
|
||||
#define isaac_step(mix, a, b, mm, m, off, r) \
|
||||
( \
|
||||
a = ((a) ^ (mix)) + (m)[off], \
|
||||
x = *(m), \
|
||||
*(m) = y = ind (mm, x) + (a) + (b), \
|
||||
*(r) = b = ind (mm, (y) >> ISAAC_LOG) + x \
|
||||
)
|
||||
|
||||
/* Use and update *S to generate random data to fill R. */
|
||||
void
|
||||
isaac_refill (struct isaac_state *s, uint32_t r[ISAAC_WORDS])
|
||||
{
|
||||
uint32_t a, b; /* Caches of a and b */
|
||||
uint32_t x, y; /* Temps needed by isaac_step macro */
|
||||
uint32_t *m = s->mm; /* Pointer into state array */
|
||||
|
||||
a = s->a;
|
||||
b = s->b + (++s->c);
|
||||
|
||||
do
|
||||
{
|
||||
isaac_step (a << 13, a, b, s->mm, m, ISAAC_WORDS / 2, r);
|
||||
isaac_step (a >> 6, a, b, s->mm, m + 1, ISAAC_WORDS / 2, r + 1);
|
||||
isaac_step (a << 2, a, b, s->mm, m + 2, ISAAC_WORDS / 2, r + 2);
|
||||
isaac_step (a >> 16, a, b, s->mm, m + 3, ISAAC_WORDS / 2, r + 3);
|
||||
r += 4;
|
||||
}
|
||||
while ((m += 4) < s->mm + ISAAC_WORDS / 2);
|
||||
do
|
||||
{
|
||||
isaac_step (a << 13, a, b, s->mm, m, -ISAAC_WORDS / 2, r);
|
||||
isaac_step (a >> 6, a, b, s->mm, m + 1, -ISAAC_WORDS / 2, r + 1);
|
||||
isaac_step (a << 2, a, b, s->mm, m + 2, -ISAAC_WORDS / 2, r + 2);
|
||||
isaac_step (a >> 16, a, b, s->mm, m + 3, -ISAAC_WORDS / 2, r + 3);
|
||||
r += 4;
|
||||
}
|
||||
while ((m += 4) < s->mm + ISAAC_WORDS);
|
||||
s->a = a;
|
||||
s->b = b;
|
||||
}
|
||||
|
||||
/*
|
||||
* The basic seed-scrambling step for initialization, based on Bob
|
||||
* Jenkins' 256-bit hash.
|
||||
*/
|
||||
#define mix(a,b,c,d,e,f,g,h) \
|
||||
( a ^= b << 11, d += a, \
|
||||
b += c, b ^= c >> 2, e += b, \
|
||||
c += d, c ^= d << 8, f += c, \
|
||||
d += e, d ^= e >> 16, g += d, \
|
||||
e += f, e ^= f << 10, h += e, \
|
||||
f += g, f ^= g >> 4, a += f, \
|
||||
g += h, g ^= h << 8, b += g, \
|
||||
h += a, h ^= a >> 9, c += h, \
|
||||
a += b )
|
||||
|
||||
/* The basic ISAAC initialization pass. */
|
||||
static void
|
||||
isaac_mix (struct isaac_state *s, uint32_t const seed[/* ISAAC_WORDS */])
|
||||
{
|
||||
int i;
|
||||
uint32_t a = s->iv[0];
|
||||
uint32_t b = s->iv[1];
|
||||
uint32_t c = s->iv[2];
|
||||
uint32_t d = s->iv[3];
|
||||
uint32_t e = s->iv[4];
|
||||
uint32_t f = s->iv[5];
|
||||
uint32_t g = s->iv[6];
|
||||
uint32_t h = s->iv[7];
|
||||
|
||||
for (i = 0; i < ISAAC_WORDS; i += 8)
|
||||
{
|
||||
a += seed[i];
|
||||
b += seed[i + 1];
|
||||
c += seed[i + 2];
|
||||
d += seed[i + 3];
|
||||
e += seed[i + 4];
|
||||
f += seed[i + 5];
|
||||
g += seed[i + 6];
|
||||
h += seed[i + 7];
|
||||
|
||||
mix (a, b, c, d, e, f, g, h);
|
||||
|
||||
s->mm[i] = a;
|
||||
s->mm[i + 1] = b;
|
||||
s->mm[i + 2] = c;
|
||||
s->mm[i + 3] = d;
|
||||
s->mm[i + 4] = e;
|
||||
s->mm[i + 5] = f;
|
||||
s->mm[i + 6] = g;
|
||||
s->mm[i + 7] = h;
|
||||
}
|
||||
|
||||
s->iv[0] = a;
|
||||
s->iv[1] = b;
|
||||
s->iv[2] = c;
|
||||
s->iv[3] = d;
|
||||
s->iv[4] = e;
|
||||
s->iv[5] = f;
|
||||
s->iv[6] = g;
|
||||
s->iv[7] = h;
|
||||
}
|
||||
|
||||
#if 0 /* Provided for reference only; not used in this code */
|
||||
/*
|
||||
* Initialize the ISAAC RNG with the given seed material.
|
||||
* Its size MUST be a multiple of ISAAC_BYTES, and may be
|
||||
* stored in the s->mm array.
|
||||
*
|
||||
* This is a generalization of the original ISAAC initialization code
|
||||
* to support larger seed sizes. For seed sizes of 0 and ISAAC_BYTES,
|
||||
* it is identical.
|
||||
*/
|
||||
static void
|
||||
isaac_init (struct isaac_state *s, uint32_t const *seed, size_t seedsize)
|
||||
{
|
||||
static uint32_t const iv[8] =
|
||||
{
|
||||
0x1367df5a, 0x95d90059, 0xc3163e4b, 0x0f421ad8,
|
||||
0xd92a4a78, 0xa51a3c49, 0xc4efea1b, 0x30609119};
|
||||
int i;
|
||||
|
||||
# if 0
|
||||
/* The initialization of iv is a precomputed form of: */
|
||||
for (i = 0; i < 7; i++)
|
||||
iv[i] = 0x9e3779b9; /* the golden ratio */
|
||||
for (i = 0; i < 4; ++i) /* scramble it */
|
||||
mix (iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);
|
||||
# endif
|
||||
s->a = s->b = s->c = 0;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
s->iv[i] = iv[i];
|
||||
|
||||
if (seedsize)
|
||||
{
|
||||
/* First pass (as in reference ISAAC code) */
|
||||
isaac_mix (s, seed);
|
||||
/* Second and subsequent passes (extension to ISAAC) */
|
||||
while (seedsize -= ISAAC_BYTES)
|
||||
{
|
||||
seed += ISAAC_WORDS;
|
||||
for (i = 0; i < ISAAC_WORDS; i++)
|
||||
s->mm[i] += seed[i];
|
||||
isaac_mix (s, s->mm);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The no seed case (as in reference ISAAC code) */
|
||||
for (i = 0; i < ISAAC_WORDS; i++)
|
||||
s->mm[i] = 0;
|
||||
}
|
||||
|
||||
/* Final pass */
|
||||
isaac_mix (s, s->mm);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize *S to a somewhat-random value. */
|
||||
static void
|
||||
isaac_seed_start (struct isaac_state *s)
|
||||
{
|
||||
static uint32_t const iv[8] =
|
||||
{
|
||||
0x1367df5a, 0x95d90059, 0xc3163e4b, 0x0f421ad8,
|
||||
0xd92a4a78, 0xa51a3c49, 0xc4efea1b, 0x30609119
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* The initialization of iv is a precomputed form of: */
|
||||
int i;
|
||||
for (i = 0; i < 7; i++)
|
||||
iv[i] = 0x9e3779b9; /* the golden ratio */
|
||||
for (i = 0; i < 4; ++i) /* scramble it */
|
||||
mix (iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);
|
||||
#endif
|
||||
|
||||
memset (s->mm, 0, sizeof s->mm);
|
||||
memcpy (s->iv, iv, sizeof s->iv);
|
||||
|
||||
/* s->c gets used for a data pointer during the seeding phase */
|
||||
s->a = s->b = s->c = 0;
|
||||
}
|
||||
|
||||
/* Add a buffer of seed material. */
|
||||
static void
|
||||
isaac_seed_data (struct isaac_state *s, void const *buffer, size_t size)
|
||||
{
|
||||
unsigned char const *buf = buffer;
|
||||
unsigned char *p;
|
||||
size_t avail;
|
||||
size_t i;
|
||||
|
||||
avail = sizeof s->mm - s->c; /* s->c is used as a write pointer */
|
||||
|
||||
/* Do any full buffers that are necessary */
|
||||
while (size > avail)
|
||||
{
|
||||
p = (unsigned char *) s->mm + s->c;
|
||||
for (i = 0; i < avail; i++)
|
||||
p[i] ^= buf[i];
|
||||
buf += avail;
|
||||
size -= avail;
|
||||
isaac_mix (s, s->mm);
|
||||
s->c = 0;
|
||||
avail = sizeof s->mm;
|
||||
}
|
||||
|
||||
/* And the final partial block */
|
||||
p = (unsigned char *) s->mm + s->c;
|
||||
for (i = 0; i < size; i++)
|
||||
p[i] ^= buf[i];
|
||||
s->c = size;
|
||||
}
|
||||
|
||||
|
||||
/* End of seeding phase; get everything ready to produce output. */
|
||||
static void
|
||||
isaac_seed_finish (struct isaac_state *s)
|
||||
{
|
||||
isaac_mix (s, s->mm);
|
||||
isaac_mix (s, s->mm);
|
||||
/* Now reinitialize c to start things off right */
|
||||
s->c = 0;
|
||||
}
|
||||
#define ISAAC_SEED(s,x) isaac_seed_data (s, &(x), sizeof (x))
|
||||
|
||||
/* Initialize *S to a somewhat-random value; this starts seeding,
|
||||
seeds with somewhat-random data, and finishes seeding. */
|
||||
void
|
||||
isaac_seed (struct isaac_state *s)
|
||||
{
|
||||
isaac_seed_start (s);
|
||||
|
||||
{ pid_t t = getpid (); ISAAC_SEED (s, t); }
|
||||
{ pid_t t = getppid (); ISAAC_SEED (s, t); }
|
||||
{ uid_t t = getuid (); ISAAC_SEED (s, t); }
|
||||
{ gid_t t = getgid (); ISAAC_SEED (s, t); }
|
||||
|
||||
{
|
||||
xtime_t t = gethrxtime ();
|
||||
ISAAC_SEED (s, t);
|
||||
}
|
||||
|
||||
isaac_seed_finish (s);
|
||||
}
|
||||
44
lib/rand-isaac.h
Normal file
44
lib/rand-isaac.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* Bob Jenkins's cryptographic random number generator, ISAAC.
|
||||
|
||||
Copyright (C) 1999-2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 1997, 1998, 1999 Colin Plumb.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Written by Colin Plumb. */
|
||||
|
||||
#ifndef RAND_ISAAC_H
|
||||
# define RAND_ISAAC_H
|
||||
|
||||
# include <stdint.h>
|
||||
|
||||
/* Size of the state tables to use. ISAAC_LOG should be at least 3,
|
||||
and smaller values give less security. */
|
||||
# define ISAAC_LOG 8
|
||||
# define ISAAC_WORDS (1 << ISAAC_LOG)
|
||||
# define ISAAC_BYTES (ISAAC_WORDS * sizeof (uint32_t))
|
||||
|
||||
/* RNG state variables. The members of this structure are private. */
|
||||
struct isaac_state
|
||||
{
|
||||
uint32_t mm[ISAAC_WORDS]; /* Main state array */
|
||||
uint32_t iv[8]; /* Seeding initial vector */
|
||||
uint32_t a, b, c; /* Extra index variables */
|
||||
};
|
||||
|
||||
void isaac_seed (struct isaac_state *);
|
||||
void isaac_refill (struct isaac_state *, uint32_t[ISAAC_WORDS]);
|
||||
|
||||
#endif
|
||||
230
lib/randint.c
Normal file
230
lib/randint.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/* Generate random integers.
|
||||
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "randint.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#if TEST
|
||||
# include <inttypes.h>
|
||||
# include <stdio.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
randint i;
|
||||
randint n = strtoumax (argv[1], NULL, 10);
|
||||
randint choices = strtoumax (argv[2], NULL, 10);
|
||||
char const *name = argv[3];
|
||||
struct randint_source *ints = randint_all_new (name, SIZE_MAX);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
printf ("%"PRIuMAX"\n", randint_choose (ints, choices));
|
||||
|
||||
return (randint_all_free (ints) == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(a,b) ((a) < (b) ? (b) : (a))
|
||||
#endif
|
||||
|
||||
/* A source of random data for generating random integers. */
|
||||
struct randint_source
|
||||
{
|
||||
/* The source of random bytes. */
|
||||
struct randread_source *source;
|
||||
|
||||
/* RANDNUM is a buffered random integer, whose information has not
|
||||
yet been delivered to the caller. It is uniformly distributed in
|
||||
the range 0 <= RANDNUM <= RANDMAX. If RANDMAX is zero, then
|
||||
RANDNUM must be zero (and in some sense it is not really
|
||||
"random"). */
|
||||
randint randnum;
|
||||
randint randmax;
|
||||
};
|
||||
|
||||
/* Create a new randint_source from SOURCE. */
|
||||
|
||||
struct randint_source *
|
||||
randint_new (struct randread_source *source)
|
||||
{
|
||||
struct randint_source *s = xmalloc (sizeof *s);
|
||||
s->source = source;
|
||||
s->randnum = s->randmax = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Create a new randint_source by creating a randread_source from
|
||||
NAME and ESTIMATED_BYTES. Return NULL (setting errno) if
|
||||
unsuccessful. */
|
||||
|
||||
struct randint_source *
|
||||
randint_all_new (char const *name, size_t bytes_bound)
|
||||
{
|
||||
struct randread_source *source = randread_new (name, bytes_bound);
|
||||
return (source ? randint_new (source) : NULL);
|
||||
}
|
||||
|
||||
/* Return the random data source of *S. */
|
||||
|
||||
struct randread_source *
|
||||
randint_get_source (struct randint_source const *s)
|
||||
{
|
||||
return s->source;
|
||||
}
|
||||
|
||||
/* HUGE_BYTES is true on hosts hosts where randint and unsigned char
|
||||
have the same width and where shifting by the word size therefore
|
||||
has undefined behavior. */
|
||||
enum { HUGE_BYTES = RANDINT_MAX == UCHAR_MAX };
|
||||
|
||||
/* Return X shifted left by CHAR_BIT bits. */
|
||||
static inline randint shift_left (randint x)
|
||||
{
|
||||
return HUGE_BYTES ? 0 : x << CHAR_BIT;
|
||||
}
|
||||
|
||||
/* Return X shifted right by CHAR_BIT bits. */
|
||||
static inline randint
|
||||
shift_right (randint x)
|
||||
{
|
||||
return HUGE_BYTES ? 0 : x >> CHAR_BIT;
|
||||
}
|
||||
|
||||
|
||||
/* Consume random data from *S to generate a random number in the range
|
||||
0 .. GENMAX. */
|
||||
|
||||
randint
|
||||
randint_genmax (struct randint_source *s, randint genmax)
|
||||
{
|
||||
struct randread_source *source = s->source;
|
||||
randint randnum = s->randnum;
|
||||
randint randmax = s->randmax;
|
||||
randint choices = genmax + 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (randmax < genmax)
|
||||
{
|
||||
/* Calculate how many input bytes will be needed, and read
|
||||
the bytes. */
|
||||
|
||||
size_t i = 0;
|
||||
randint rmax = randmax;
|
||||
unsigned char buf[sizeof randnum];
|
||||
|
||||
do
|
||||
{
|
||||
rmax = shift_left (rmax) + UCHAR_MAX;
|
||||
i++;
|
||||
}
|
||||
while (rmax < genmax);
|
||||
|
||||
randread (source, buf, i);
|
||||
|
||||
/* Increase RANDMAX by appending random bytes to RANDNUM and
|
||||
UCHAR_MAX to RANDMAX until RANDMAX is no less than
|
||||
GENMAX. This may lose up to CHAR_BIT bits of information
|
||||
if shift_right (RANDINT_MAX) < GENMAX, but it is not
|
||||
worth the programming hassle of saving these bits since
|
||||
GENMAX is rarely that large in practice. */
|
||||
|
||||
i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
randnum = shift_left (randnum) + buf[i];
|
||||
randmax = shift_left (randmax) + UCHAR_MAX;
|
||||
i++;
|
||||
}
|
||||
while (randmax < genmax);
|
||||
}
|
||||
|
||||
if (randmax == genmax)
|
||||
{
|
||||
s->randnum = s->randmax = 0;
|
||||
return randnum;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* GENMAX < RANDMAX, so attempt to generate a random number
|
||||
by taking RANDNUM modulo GENMAX+1. This will choose
|
||||
fairly so long as RANDNUM falls within an integral
|
||||
multiple of GENMAX+1; otherwise, LAST_USABLE_CHOICE < RANDNUM,
|
||||
so discard this attempt and try again.
|
||||
|
||||
Since GENMAX cannot be RANDINT_MAX, CHOICES cannot be
|
||||
zero and there is no need to worry about dividing by
|
||||
zero. */
|
||||
|
||||
randint excess_choices = randmax - genmax;
|
||||
randint unusable_choices = excess_choices % choices;
|
||||
randint last_usable_choice = randmax - unusable_choices;
|
||||
randint reduced_randnum = randnum % choices;
|
||||
|
||||
if (randnum <= last_usable_choice)
|
||||
{
|
||||
s->randnum = randnum / choices;
|
||||
s->randmax = excess_choices / choices;
|
||||
return reduced_randnum;
|
||||
}
|
||||
|
||||
/* Retry, but retain the randomness from the fact that RANDNUM fell
|
||||
into the range LAST_USABLE_CHOICE+1 .. RANDMAX. */
|
||||
randnum = reduced_randnum;
|
||||
randmax = unusable_choices - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear *S so that it no longer contains undelivered random data. */
|
||||
|
||||
void
|
||||
randint_free (struct randint_source *s)
|
||||
{
|
||||
memset (s, 0, sizeof *s);
|
||||
free (s);
|
||||
}
|
||||
|
||||
/* Likewise, but also clear the underlying randread object. Return
|
||||
0 if successful, -1 (setting errno) otherwise. */
|
||||
|
||||
int
|
||||
randint_all_free (struct randint_source *s)
|
||||
{
|
||||
int r = randread_free (s->source);
|
||||
int e = errno;
|
||||
randint_free (s);
|
||||
errno = e;
|
||||
return r;
|
||||
}
|
||||
52
lib/randint.h
Normal file
52
lib/randint.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* Generate random integers.
|
||||
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#ifndef RANDINT_H
|
||||
|
||||
# define RANDINT_H 1
|
||||
|
||||
# include <stdint.h>
|
||||
|
||||
# include "randread.h"
|
||||
|
||||
/* An unsigned integer type, used for random integers, and its maximum
|
||||
value. */
|
||||
typedef uintmax_t randint;
|
||||
# define RANDINT_MAX UINTMAX_MAX
|
||||
|
||||
struct randint_source;
|
||||
|
||||
struct randint_source *randint_new (struct randread_source *);
|
||||
struct randint_source *randint_all_new (char const *, size_t);
|
||||
struct randread_source *randint_get_source (struct randint_source const *);
|
||||
randint randint_genmax (struct randint_source *, randint genmax);
|
||||
|
||||
/* Consume random data from *S to generate a random number in the range
|
||||
0 .. CHOICES-1. CHOICES must be nonzero. */
|
||||
static inline randint
|
||||
randint_choose (struct randint_source *s, randint choices)
|
||||
{
|
||||
return randint_genmax (s, choices - 1);
|
||||
}
|
||||
|
||||
void randint_free (struct randint_source *);
|
||||
int randint_all_free (struct randint_source *);
|
||||
|
||||
#endif
|
||||
105
lib/randperm.c
Normal file
105
lib/randperm.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/* Generate random permutations.
|
||||
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "randperm.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "xalloc.h"
|
||||
|
||||
/* Return the ceiling of the log base 2 of N. If N is zero, return
|
||||
an unspecified value. */
|
||||
|
||||
static size_t
|
||||
ceil_lg (size_t n)
|
||||
{
|
||||
size_t b = 0;
|
||||
for (n--; n != 0; n /= 2)
|
||||
b++;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Return an upper bound on the number of random bytes needed to
|
||||
generate the first H elements of a random permutation of N
|
||||
elements. H must not exceed N. */
|
||||
|
||||
size_t
|
||||
randperm_bound (size_t h, size_t n)
|
||||
{
|
||||
/* Upper bound on number of bits needed to generate the first number
|
||||
of the permutation. */
|
||||
size_t lg_n = ceil_lg (n);
|
||||
|
||||
/* Upper bound on number of bits needed to generated the first H elements. */
|
||||
size_t ar = lg_n * h;
|
||||
|
||||
/* Convert the bit count to a byte count. */
|
||||
size_t bound = (ar + CHAR_BIT - 1) / CHAR_BIT;
|
||||
|
||||
return bound;
|
||||
}
|
||||
|
||||
/* From R, allocate and return the first H elements of a random
|
||||
permutation of N elements. H must not exceed N. Return NULL if H
|
||||
is zero. */
|
||||
|
||||
size_t *
|
||||
randperm_new (struct randint_source *r, size_t h, size_t n)
|
||||
{
|
||||
size_t *v;
|
||||
|
||||
switch (h)
|
||||
{
|
||||
case 0:
|
||||
v = NULL;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
v = xmalloc (sizeof *v);
|
||||
v[0] = randint_choose (r, n);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
size_t i;
|
||||
|
||||
v = xnmalloc (n, sizeof *v);
|
||||
for (i = 0; i < n; i++)
|
||||
v[i] = i;
|
||||
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
size_t j = i + randint_choose (r, n - i);
|
||||
size_t t = v[i];
|
||||
v[i] = v[j];
|
||||
v[j] = t;
|
||||
}
|
||||
|
||||
v = xnrealloc (v, h, sizeof *v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
4
lib/randperm.h
Normal file
4
lib/randperm.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "randint.h"
|
||||
#include <stddef.h>
|
||||
size_t randperm_bound (size_t, size_t);
|
||||
size_t *randperm_new (struct randint_source *, size_t, size_t);
|
||||
298
lib/randread.c
Normal file
298
lib/randread.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/* Generate buffers of random data.
|
||||
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "randread.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <exitfail.h>
|
||||
#include <quotearg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gettext.h"
|
||||
#define _(msgid) gettext (msgid)
|
||||
|
||||
#include "rand-isaac.h"
|
||||
#include "stdio-safer.h"
|
||||
#include "unlocked-io.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
|
||||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
#if _STRING_ARCH_unaligned
|
||||
# define ALIGNED_POINTER(ptr, type) true
|
||||
#else
|
||||
# define alignof(type) offsetof (struct { char c; type x; }, x)
|
||||
# define ALIGNED_POINTER(ptr, type) ((size_t) (ptr) % alignof (type) == 0)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_RANDOM_FILE
|
||||
# define DEFAULT_RANDOM_FILE "/dev/urandom"
|
||||
#endif
|
||||
|
||||
/* The maximum buffer size used for reads of random data. Using the
|
||||
value 2 * ISAAC_BYTES makes this the largest power of two that
|
||||
would not otherwise cause struct randread_source to grow. */
|
||||
#define RANDREAD_BUFFER_SIZE (2 * ISAAC_BYTES)
|
||||
|
||||
/* A source of random data for generating random buffers. */
|
||||
struct randread_source
|
||||
{
|
||||
/* Stream to read random bytes from. If null, the behavior is
|
||||
undefined; the current implementation uses ISAAC in this case,
|
||||
but this is for old-fashioned implementations that lack
|
||||
/dev/urandom and callers should not rely on this. */
|
||||
FILE *source;
|
||||
|
||||
/* Function to call, and its argument, if there is an input error or
|
||||
end of file when reading from the stream; errno is nonzero if
|
||||
there was an error. If this function returns, it should fix the
|
||||
problem before returning. The default handler assumes that
|
||||
handler_arg is the file name of the source. */
|
||||
void (*handler) (void *);
|
||||
void *handler_arg;
|
||||
|
||||
/* The buffer for SOURCE. It's kept here to simplify storage
|
||||
allocation and to make it easier to clear out buffered random
|
||||
data. */
|
||||
union
|
||||
{
|
||||
/* The stream buffer, if SOURCE is not null. */
|
||||
char c[RANDREAD_BUFFER_SIZE];
|
||||
|
||||
/* The buffered ISAAC pseudorandom buffer, if SOURCE is null. */
|
||||
struct isaac
|
||||
{
|
||||
/* The number of bytes that are buffered at the end of data.b. */
|
||||
size_t buffered;
|
||||
|
||||
/* State of the ISAAC generator. */
|
||||
struct isaac_state state;
|
||||
|
||||
/* Up to a buffer's worth of pseudorandom data. */
|
||||
union
|
||||
{
|
||||
uint32_t w[ISAAC_WORDS];
|
||||
unsigned char b[ISAAC_BYTES];
|
||||
} data;
|
||||
} isaac;
|
||||
} buf;
|
||||
};
|
||||
|
||||
|
||||
/* The default error handler. */
|
||||
|
||||
static void
|
||||
randread_error (void *file_name)
|
||||
{
|
||||
if (file_name)
|
||||
error (exit_failure, errno,
|
||||
_(errno == 0 ? "%s: end of file" : "%s: read error"),
|
||||
quotearg_colon (file_name));
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Simply return a new randread_source object with the default error
|
||||
handler. */
|
||||
|
||||
static struct randread_source *
|
||||
simple_new (FILE *source, void *handler_arg)
|
||||
{
|
||||
struct randread_source *s = xmalloc (sizeof *s);
|
||||
s->source = source;
|
||||
s->handler = randread_error;
|
||||
s->handler_arg = handler_arg;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Create and initialize a random data source from NAME, or use a
|
||||
reasonable default source if NAME is null. BYTES_BOUND is an upper
|
||||
bound on the number of bytes that will be needed. If zero, it is a
|
||||
hard bound; otherwise it is just an estimate.
|
||||
|
||||
If NAME is not null, NAME is saved for use as the argument of the
|
||||
default handler. Unless a non-default handler is used, NAME's
|
||||
lifetime should be at least that of the returned value.
|
||||
|
||||
Return NULL (setting errno) on failure. */
|
||||
|
||||
struct randread_source *
|
||||
randread_new (char const *name, size_t bytes_bound)
|
||||
{
|
||||
if (bytes_bound == 0)
|
||||
return simple_new (NULL, NULL);
|
||||
else
|
||||
{
|
||||
char const *file_name = (name ? name : DEFAULT_RANDOM_FILE);
|
||||
FILE *source = fopen_safer (file_name, "rb");
|
||||
struct randread_source *s;
|
||||
|
||||
if (! source)
|
||||
{
|
||||
if (name)
|
||||
return NULL;
|
||||
file_name = NULL;
|
||||
}
|
||||
|
||||
s = simple_new (source, (void *) file_name);
|
||||
|
||||
if (source)
|
||||
setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound));
|
||||
else
|
||||
{
|
||||
s->buf.isaac.buffered = 0;
|
||||
isaac_seed (&s->buf.isaac.state);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Set S's handler and its argument. HANDLER (HANDLER_ARG) is called
|
||||
when there is a read error or end of file from the random data
|
||||
source; errno is nonzero if there was an error. If HANDLER
|
||||
returns, it should fix the problem before returning. The default
|
||||
handler assumes that handler_arg is the file name of the source; it
|
||||
does not return. */
|
||||
|
||||
void
|
||||
randread_set_handler (struct randread_source *s, void (*handler) (void *))
|
||||
{
|
||||
s->handler = handler;
|
||||
}
|
||||
|
||||
void
|
||||
randread_set_handler_arg (struct randread_source *s, void *handler_arg)
|
||||
{
|
||||
s->handler_arg = handler_arg;
|
||||
}
|
||||
|
||||
|
||||
/* Place SIZE random bytes into the buffer beginning at P, using
|
||||
the stream in S. */
|
||||
|
||||
static void
|
||||
readsource (struct randread_source *s, unsigned char *p, size_t size)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
size_t inbytes = fread (p, sizeof *p, size, s->source);
|
||||
int fread_errno = errno;
|
||||
p += inbytes;
|
||||
size -= inbytes;
|
||||
if (size == 0)
|
||||
break;
|
||||
errno = (ferror (s->source) ? fread_errno : 0);
|
||||
s->handler (s->handler_arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Place SIZE pseudorandom bytes into the buffer beginning at P, using
|
||||
the buffered ISAAC generator in ISAAC. */
|
||||
|
||||
static void
|
||||
readisaac (struct isaac *isaac, unsigned char *p, size_t size)
|
||||
{
|
||||
size_t inbytes = isaac->buffered;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (size <= inbytes)
|
||||
{
|
||||
memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, size);
|
||||
isaac->buffered = inbytes - size;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, inbytes);
|
||||
p += inbytes;
|
||||
size -= inbytes;
|
||||
|
||||
/* If P is aligned, write to *P directly to avoid the overhead
|
||||
of copying from the buffer. */
|
||||
if (ALIGNED_POINTER (p, uint32_t))
|
||||
{
|
||||
uint32_t *wp = (uint32_t *) p;
|
||||
while (ISAAC_BYTES <= size)
|
||||
{
|
||||
isaac_refill (&isaac->state, wp);
|
||||
wp += ISAAC_WORDS;
|
||||
size -= ISAAC_BYTES;
|
||||
if (size == 0)
|
||||
{
|
||||
isaac->buffered = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
p = (unsigned char *) wp;
|
||||
}
|
||||
|
||||
isaac_refill (&isaac->state, isaac->data.w);
|
||||
inbytes = ISAAC_BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Consume random data from *S to generate a random buffer BUF of size
|
||||
SIZE. */
|
||||
|
||||
void
|
||||
randread (struct randread_source *s, void *buf, size_t size)
|
||||
{
|
||||
if (s->source)
|
||||
readsource (s, buf, size);
|
||||
else
|
||||
readisaac (&s->buf.isaac, buf, size);
|
||||
}
|
||||
|
||||
|
||||
/* Clear *S so that it no longer contains undelivered random data, and
|
||||
deallocate any system resources associated with *S. Return 0 if
|
||||
successful, a negative number (setting errno) if not (this is rare,
|
||||
but can occur in theory if there is an input error). */
|
||||
|
||||
int
|
||||
randread_free (struct randread_source *s)
|
||||
{
|
||||
FILE *source = s->source;
|
||||
memset (s, 0, sizeof *s);
|
||||
free (s);
|
||||
return (source ? fclose (source) : 0);
|
||||
}
|
||||
34
lib/randread.h
Normal file
34
lib/randread.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Generate buffers of random data.
|
||||
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#ifndef RANDREAD_H
|
||||
# define RANDREAD_H 1
|
||||
|
||||
# include <stddef.h>
|
||||
|
||||
struct randread_source;
|
||||
|
||||
struct randread_source *randread_new (char const *, size_t);
|
||||
void randread (struct randread_source *, void *, size_t);
|
||||
void randread_set_handler (struct randread_source *, void (*) (void *));
|
||||
void randread_set_handler_arg (struct randread_source *, void *);
|
||||
int randread_free (struct randread_source *);
|
||||
|
||||
#endif
|
||||
65
lib/xmemxfrm.c
Normal file
65
lib/xmemxfrm.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/* Locale-specific memory transformation
|
||||
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Written by Paul Eggert <eggert@cs.ucla.edu>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "xmemxfrm.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gettext.h"
|
||||
#define _(msgid) gettext (msgid)
|
||||
|
||||
#include "error.h"
|
||||
#include "exitfail.h"
|
||||
#include "memxfrm.h"
|
||||
#include "quotearg.h"
|
||||
|
||||
/* Store into DEST (of size DESTSIZE) the text in SRC (of size
|
||||
SRCSIZE) transformed so that the result of memcmp on two
|
||||
transformed texts (with ties going to the longer text) is the same
|
||||
as the result of memcoll on the two texts before their
|
||||
transformation. Perhaps temporarily modify the byte after SRC, but
|
||||
restore its original contents before returning.
|
||||
|
||||
Return the size of the resulting text. DEST contains an
|
||||
indeterminate value if the resulting size is greater than DESTSIZE.
|
||||
Report an error and exit if there is an error. */
|
||||
|
||||
size_t
|
||||
xmemxfrm (char *restrict dest, size_t destsize,
|
||||
char *restrict src, size_t srcsize)
|
||||
{
|
||||
size_t translated_size = memxfrm (dest, destsize, src, srcsize);
|
||||
|
||||
if (errno)
|
||||
{
|
||||
error (0, errno, _("string transformation failed"));
|
||||
error (0, 0, _("Set LC_ALL='C' to work around the problem."));
|
||||
error (exit_failure, 0,
|
||||
_("The untransformed string was %s."),
|
||||
quotearg_n_style_mem (0, locale_quoting_style, src, srcsize));
|
||||
}
|
||||
|
||||
return translated_size;
|
||||
}
|
||||
2
lib/xmemxfrm.h
Normal file
2
lib/xmemxfrm.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#include <stddef.h>
|
||||
size_t xmemxfrm (char *restrict, size_t, char *restrict, size_t);
|
||||
15
m4/memxfrm.m4
Normal file
15
m4/memxfrm.m4
Normal file
@@ -0,0 +1,15 @@
|
||||
dnl Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
AC_DEFUN([gl_MEMXFRM],
|
||||
[
|
||||
AC_LIBSOURCES([memxfrm.c, memxfrm.h])
|
||||
AC_LIBOBJ([memxfrm])
|
||||
|
||||
AC_REQUIRE([AC_C_RESTRICT])
|
||||
|
||||
dnl Prerequisites of lib/memcoll.c.
|
||||
AC_CHECK_FUNCS_ONCE([strxfrm])
|
||||
])
|
||||
12
m4/randint.m4
Normal file
12
m4/randint.m4
Normal file
@@ -0,0 +1,12 @@
|
||||
dnl Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
AC_DEFUN([gl_RANDINT],
|
||||
[
|
||||
AC_LIBSOURCES([randint.c, randint.h])
|
||||
AC_LIBOBJ([randint])
|
||||
|
||||
AC_REQUIRE([AC_C_INLINE])
|
||||
])
|
||||
10
m4/randperm.m4
Normal file
10
m4/randperm.m4
Normal file
@@ -0,0 +1,10 @@
|
||||
dnl Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
AC_DEFUN([gl_RANDPERM],
|
||||
[
|
||||
AC_LIBSOURCES([randperm.c, randperm.h])
|
||||
AC_LIBOBJ([randperm])
|
||||
])
|
||||
11
m4/randread.m4
Normal file
11
m4/randread.m4
Normal file
@@ -0,0 +1,11 @@
|
||||
dnl Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
AC_DEFUN([gl_RANDREAD],
|
||||
[
|
||||
AC_LIBSOURCES([randread.c, randread.h, rand-isaac.c, rand-isaac.h])
|
||||
AC_LIBOBJ([randread])
|
||||
AC_LIBOBJ([rand-isaac])
|
||||
])
|
||||
4
man/shuf.x
Normal file
4
man/shuf.x
Normal file
@@ -0,0 +1,4 @@
|
||||
[NAME]
|
||||
shuf \- generate random permutations
|
||||
[DESCRIPTION]
|
||||
.\" Add any additional description here
|
||||
401
src/shuf.c
Normal file
401
src/shuf.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/* Shuffle lines of text.
|
||||
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Written by Paul Eggert. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "getopt.h"
|
||||
#include "quote.h"
|
||||
#include "quotearg.h"
|
||||
#include "randint.h"
|
||||
#include "randperm.h"
|
||||
#include "xstrtol.h"
|
||||
|
||||
/* The official name of this program (e.g., no `g' prefix). */
|
||||
#define PROGRAM_NAME "shuf"
|
||||
|
||||
#define AUTHORS "Paul Eggert"
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
else
|
||||
{
|
||||
printf (_("\
|
||||
Usage: %s [OPTION]... [FILE]\n\
|
||||
or: %s -e [OPTION]... [ARG]...\n\
|
||||
or: %s -i LO-HI [OPTION]...\n\
|
||||
"),
|
||||
program_name, program_name, program_name);
|
||||
fputs (_("\
|
||||
Write a random permutation of the input lines to standard output.\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-e, --echo treat each ARG as an input line\n\
|
||||
-i, --input-range=LO-HI treat each number LO through HI as an input line\n\
|
||||
-n, --head-lines=LINES output at most LINES lines\n\
|
||||
-o, --output=FILE write result to FILE instead of standard output\n\
|
||||
--random-source=FILE get random bytes from FILE (default /dev/urandom)\n\
|
||||
-z, --zero-terminated end lines with 0 byte, not newline\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
fputs (_("\
|
||||
\n\
|
||||
With no FILE, or when FILE is -, read standard input.\n\
|
||||
"), stdout);
|
||||
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
|
||||
}
|
||||
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* For long options that have no equivalent short option, use a
|
||||
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
|
||||
enum
|
||||
{
|
||||
RANDOM_SOURCE_OPTION = CHAR_MAX + 1
|
||||
};
|
||||
|
||||
static struct option const long_opts[] =
|
||||
{
|
||||
{"echo", no_argument, NULL, 'e'},
|
||||
{"input-range", required_argument, NULL, 'i'},
|
||||
{"head-count", required_argument, NULL, 'n'},
|
||||
{"output", required_argument, NULL, 'o'},
|
||||
{"random-source", required_argument, NULL, RANDOM_SOURCE_OPTION},
|
||||
{"zero-terminated", no_argument, NULL, 'z'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
static bool
|
||||
input_numbers_option_used (size_t lo_input, size_t hi_input)
|
||||
{
|
||||
return ! (lo_input == SIZE_MAX && hi_input == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
input_from_argv (char **operand, int n_operands, char eolbyte)
|
||||
{
|
||||
char *p;
|
||||
size_t size = n_operands;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_operands; i++)
|
||||
size += strlen (operand[i]);
|
||||
p = xmalloc (size);
|
||||
|
||||
for (i = 0; i < n_operands; i++)
|
||||
{
|
||||
char *p1 = stpcpy (p, operand[i]);
|
||||
operand[i] = p;
|
||||
p = p1;
|
||||
*p++ = eolbyte;
|
||||
}
|
||||
|
||||
operand[n_operands] = p;
|
||||
}
|
||||
|
||||
/* Read data from file IN. Input lines are delimited by EOLBYTE;
|
||||
silently append a trailing EOLBYTE if the file ends in some other
|
||||
byte. Store a pointer to the resulting array of lines into *PLINE.
|
||||
Return the number of lines read. Report an error and exit on
|
||||
failure. */
|
||||
|
||||
static size_t
|
||||
read_input (FILE *in, char eolbyte, char ***pline)
|
||||
{
|
||||
char *p;
|
||||
char *buf = NULL;
|
||||
char *lim;
|
||||
size_t alloc = 0;
|
||||
size_t used = 0;
|
||||
size_t next_alloc = (1 << 13) + 1;
|
||||
size_t bytes_to_read;
|
||||
size_t nread;
|
||||
char **line;
|
||||
size_t i;
|
||||
size_t n_lines;
|
||||
int fread_errno;
|
||||
struct stat instat;
|
||||
|
||||
if (fstat (fileno (in), &instat) == 0 && S_ISREG (instat.st_mode))
|
||||
{
|
||||
off_t file_size = instat.st_size;
|
||||
off_t current_offset = ftello (in);
|
||||
if (0 <= current_offset)
|
||||
{
|
||||
off_t remaining_size =
|
||||
(current_offset < file_size ? file_size - current_offset : 0);
|
||||
if (SIZE_MAX - 2 < remaining_size)
|
||||
xalloc_die ();
|
||||
next_alloc = remaining_size + 2;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (alloc == used)
|
||||
{
|
||||
if (alloc == SIZE_MAX)
|
||||
xalloc_die ();
|
||||
alloc = next_alloc;
|
||||
next_alloc = alloc * 2;
|
||||
if (next_alloc < alloc)
|
||||
next_alloc = SIZE_MAX;
|
||||
buf = xrealloc (buf, alloc);
|
||||
}
|
||||
|
||||
bytes_to_read = alloc - used - 1;
|
||||
nread = fread (buf + used, sizeof (char), bytes_to_read, in);
|
||||
used += nread;
|
||||
}
|
||||
while (nread == bytes_to_read);
|
||||
|
||||
fread_errno = errno;
|
||||
|
||||
if (used && buf[used - 1] != eolbyte)
|
||||
buf[used++] = eolbyte;
|
||||
|
||||
lim = buf + used;
|
||||
|
||||
n_lines = 0;
|
||||
for (p = buf; p < lim; p = memchr (p, eolbyte, lim - p) + 1)
|
||||
n_lines++;
|
||||
|
||||
*pline = line = xnmalloc (n_lines + 1, sizeof *line);
|
||||
|
||||
line[0] = p = buf;
|
||||
for (i = 1; i <= n_lines; i++)
|
||||
line[i] = p = memchr (p, eolbyte, lim - p) + 1;
|
||||
|
||||
errno = fread_errno;
|
||||
return n_lines;
|
||||
}
|
||||
|
||||
static int
|
||||
write_permuted_output (size_t n_lines, char * const *line, size_t lo_input,
|
||||
size_t const *permutation)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (line)
|
||||
for (i = 0; i < n_lines; i++)
|
||||
{
|
||||
char * const *p = line + permutation[i];
|
||||
size_t len = p[1] - p[0];
|
||||
if (fwrite (p[0], sizeof *p[0], len, stdout) != len)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
for (i = 0; i < n_lines; i++)
|
||||
{
|
||||
unsigned long int n = lo_input + permutation[i];
|
||||
if (printf ("%lu\n", n) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
bool echo = false;
|
||||
size_t lo_input = SIZE_MAX;
|
||||
size_t hi_input = 0;
|
||||
size_t head_lines = SIZE_MAX;
|
||||
char const *outfile = NULL;
|
||||
char *random_source = NULL;
|
||||
char eolbyte = '\n';
|
||||
|
||||
int optc;
|
||||
int n_operands;
|
||||
char **operand;
|
||||
size_t n_lines;
|
||||
char **line;
|
||||
struct randint_source *randint_source;
|
||||
size_t const *permutation;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "ei:n:o:z", long_opts, NULL)) != -1)
|
||||
switch (optc)
|
||||
{
|
||||
case 'e':
|
||||
echo = true;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
{
|
||||
unsigned long int argval = 0;
|
||||
char *p = strchr (optarg, '-');
|
||||
bool invalid = !p;
|
||||
|
||||
if (input_numbers_option_used (lo_input, hi_input))
|
||||
error (EXIT_FAILURE, 0, _("multiple -i options specified"));
|
||||
|
||||
if (p)
|
||||
{
|
||||
*p = '\0';
|
||||
invalid = ((xstrtoul (optarg, NULL, 10, &argval, NULL)
|
||||
!= LONGINT_OK)
|
||||
|| SIZE_MAX < argval);
|
||||
*p = '-';
|
||||
lo_input = argval;
|
||||
optarg = p + 1;
|
||||
}
|
||||
|
||||
invalid |= ((xstrtoul (optarg, NULL, 10, &argval, NULL)
|
||||
!= LONGINT_OK)
|
||||
|| SIZE_MAX < argval);
|
||||
hi_input = argval;
|
||||
n_lines = hi_input - lo_input + 1;
|
||||
invalid |= ((lo_input <= hi_input) == (n_lines == 0));
|
||||
if (invalid)
|
||||
error (EXIT_FAILURE, 0, _("invalid input range %s"),
|
||||
quote (optarg));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
{
|
||||
unsigned long int argval;
|
||||
strtol_error e = xstrtoul (optarg, NULL, 10, &argval, NULL);
|
||||
|
||||
if (e == LONGINT_OK)
|
||||
head_lines = MIN (head_lines, argval);
|
||||
else if (e != LONGINT_OVERFLOW)
|
||||
error (EXIT_FAILURE, 0, _("invalid line count %s"),
|
||||
quote (optarg));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (outfile && !STREQ (outfile, optarg))
|
||||
error (EXIT_FAILURE, 0, _("multiple output files specified"));
|
||||
outfile = optarg;
|
||||
break;
|
||||
|
||||
case RANDOM_SOURCE_OPTION:
|
||||
if (random_source && !STREQ (random_source, optarg))
|
||||
error (EXIT_FAILURE, 0, _("multiple random sources specified"));
|
||||
random_source = optarg;
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
eolbyte = '\0';
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
n_operands = argc - optind;
|
||||
operand = argv + optind;
|
||||
|
||||
if (echo)
|
||||
{
|
||||
if (input_numbers_option_used (lo_input, hi_input))
|
||||
error (EXIT_FAILURE, 0, _("cannot combine -e and -i options"));
|
||||
input_from_argv (operand, n_operands, eolbyte);
|
||||
n_lines = n_operands;
|
||||
line = operand;
|
||||
}
|
||||
else if (input_numbers_option_used (lo_input, hi_input))
|
||||
{
|
||||
if (n_operands)
|
||||
{
|
||||
error (0, 0, _("extra operand %s\n"), quote (operand[0]));
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
n_lines = hi_input - lo_input + 1;
|
||||
line = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
char **input_lines;
|
||||
|
||||
switch (n_operands)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (! (STREQ (operand[0], "-") || freopen (operand[0], "r", stdin)))
|
||||
error (EXIT_FAILURE, errno, "%s", operand[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
error (0, 0, _("extra operand %s"), quote (operand[1]));
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
n_lines = read_input (stdin, eolbyte, &input_lines);
|
||||
line = input_lines;
|
||||
}
|
||||
|
||||
head_lines = MIN (head_lines, n_lines);
|
||||
|
||||
randint_source = randint_all_new (random_source,
|
||||
randperm_bound (head_lines, n_lines));
|
||||
if (! randint_source)
|
||||
error (EXIT_FAILURE, errno, "%s", quotearg_colon (random_source));
|
||||
|
||||
/* Close stdin now, rather than earlier, so that randint_all_new
|
||||
doesn't have to worry about opening something other than
|
||||
stdin. */
|
||||
if (! (echo || input_numbers_option_used (lo_input, hi_input))
|
||||
&& (ferror (stdin) || fclose (stdin) != 0))
|
||||
error (EXIT_FAILURE, errno, _("read error"));
|
||||
|
||||
permutation = randperm_new (randint_source, head_lines, n_lines);
|
||||
|
||||
if (outfile && ! freopen (outfile, "w", stdout))
|
||||
error (EXIT_FAILURE, errno, "%s", quotearg_colon (outfile));
|
||||
if (write_permuted_output (head_lines, line, lo_input, permutation) != 0)
|
||||
error (EXIT_FAILURE, errno, _("write error"));
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
37
tests/misc/shuf
Executable file
37
tests/misc/shuf
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/bin/sh
|
||||
# Ensure that shuf randomizes its input.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
shuf --version
|
||||
fi
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
seq 100 > in || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
shuf in >out || fail=1
|
||||
|
||||
# Fail if the input is the same as the output.
|
||||
# This is a probabilistic test :-)
|
||||
# However, the odds of failure are very low: 1 in 100! (~ 1 in 10^158)
|
||||
cmp in out > /dev/null && { fail=1; echo "not random?" 1>&2; }
|
||||
|
||||
# Fail if the sorted output is not the same as the input.
|
||||
sort -n out > out1
|
||||
cmp in out1 || { fail=1; echo "not a permutation" 1>&2; }
|
||||
|
||||
(exit $fail); exit $fail
|
||||
Reference in New Issue
Block a user