random.c revision 181615
12490Sjkh/*
22490Sjkh * Copyright (c) 1994
32490Sjkh *	The Regents of the University of California.  All rights reserved.
42490Sjkh *
52490Sjkh * This code is derived from software contributed to Berkeley by
62490Sjkh * Guy Harris at Network Appliance Corp.
72490Sjkh *
82490Sjkh * Redistribution and use in source and binary forms, with or without
92490Sjkh * modification, are permitted provided that the following conditions
102490Sjkh * are met:
112490Sjkh * 1. Redistributions of source code must retain the above copyright
122490Sjkh *    notice, this list of conditions and the following disclaimer.
132490Sjkh * 2. Redistributions in binary form must reproduce the above copyright
142490Sjkh *    notice, this list of conditions and the following disclaimer in the
152490Sjkh *    documentation and/or other materials provided with the distribution.
162490Sjkh * 3. All advertising materials mentioning features or use of this software
172490Sjkh *    must display the following acknowledgement:
182490Sjkh *	This product includes software developed by the University of
192490Sjkh *	California, Berkeley and its contributors.
202490Sjkh * 4. Neither the name of the University nor the names of its contributors
212490Sjkh *    may be used to endorse or promote products derived from this software
222490Sjkh *    without specific prior written permission.
232490Sjkh *
242490Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
252490Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
262490Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
272490Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
282490Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
292490Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
302490Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
312490Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
322490Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
332490Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
342490Sjkh * SUCH DAMAGE.
352490Sjkh */
362490Sjkh
37114725Sobrien#if 0
382490Sjkh#ifndef lint
3953920Sbillfstatic const char copyright[] =
402490Sjkh"@(#) Copyright (c) 1994\n\
412490Sjkh	The Regents of the University of California.  All rights reserved.\n";
422490Sjkh#endif /* not lint */
432490Sjkh
442490Sjkh#ifndef lint
45110928Sseancstatic const char sccsid[] = "@(#)random.c	8.5 (Berkeley) 4/5/94";
46114725Sobrien#endif /* not lint */
4753920Sbillf#endif
48110928Sseanc#include <sys/cdefs.h>
49110928Sseanc__FBSDID("$FreeBSD: head/games/random/random.c 181615 2008-08-11 23:24:42Z ache $");
50110928Sseanc
512490Sjkh#include <sys/types.h>
522490Sjkh
532490Sjkh#include <err.h>
542490Sjkh#include <errno.h>
55110723Sseanc#include <fcntl.h>
566160Sbde#include <limits.h>
57157758Sache#include <locale.h>
582490Sjkh#include <stdio.h>
592490Sjkh#include <stdlib.h>
60110928Sseanc#include <string.h>
612490Sjkh#include <time.h>
622490Sjkh#include <unistd.h>
63110928Sseanc
64110723Sseanc#include "randomize_fd.h"
652490Sjkh
66110928Sseancstatic void usage(void);
672490Sjkh
682490Sjkhint
69110928Sseancmain(int argc, char *argv[])
702490Sjkh{
712490Sjkh	double denom;
72110723Sseanc	int ch, fd, random_exit, randomize_lines, random_type, ret,
73110723Sseanc		selected, unique_output, unbuffer_output;
74136090Sstefanf	char *ep;
75136090Sstefanf	const char *filename;
762490Sjkh
7754482Sbillf	denom = 0;
78136090Sstefanf	filename = "/dev/fd/0";
79110723Sseanc	random_type = RANDOM_TYPE_UNSET;
80110723Sseanc	random_exit = randomize_lines = random_type = unbuffer_output = 0;
81110723Sseanc	unique_output = 1;
82157758Sache
83157758Sache	(void)setlocale(LC_CTYPE, "");
84157758Sache
85110723Sseanc	while ((ch = getopt(argc, argv, "ef:hlruUw")) != -1)
862490Sjkh		switch (ch) {
872490Sjkh		case 'e':
882490Sjkh			random_exit = 1;
892490Sjkh			break;
90110723Sseanc		case 'f':
91110723Sseanc			randomize_lines = 1;
92136090Sstefanf			if (strcmp(optarg, "-") != 0)
93110723Sseanc				filename = optarg;
94110723Sseanc			break;
95110723Sseanc		case 'l':
96110723Sseanc			randomize_lines = 1;
97110723Sseanc			random_type = RANDOM_TYPE_LINES;
98110723Sseanc			break;
992490Sjkh		case 'r':
1002490Sjkh			unbuffer_output = 1;
1012490Sjkh			break;
102110723Sseanc		case 'u':
103110723Sseanc			randomize_lines = 1;
104110723Sseanc			unique_output = 1;
105110723Sseanc			break;
106110723Sseanc		case 'U':
107110723Sseanc			randomize_lines = 1;
108110723Sseanc			unique_output = 0;
109110723Sseanc			break;
110110723Sseanc		case 'w':
111110723Sseanc			randomize_lines = 1;
112110723Sseanc			random_type = RANDOM_TYPE_WORDS;
113110723Sseanc			break;
1142490Sjkh		default:
1152490Sjkh		case '?':
1162490Sjkh			usage();
1172490Sjkh			/* NOTREACHED */
1182490Sjkh		}
1192490Sjkh
1202490Sjkh	argc -= optind;
1212490Sjkh	argv += optind;
1222490Sjkh
1232490Sjkh	switch (argc) {
1242490Sjkh	case 0:
125110723Sseanc		denom = (randomize_lines ? 1 : 2);
1262490Sjkh		break;
1272490Sjkh	case 1:
1282490Sjkh		errno = 0;
1292490Sjkh		denom = strtod(*argv, &ep);
1302490Sjkh		if (errno == ERANGE)
1312490Sjkh			err(1, "%s", *argv);
13224420Sache		if (denom <= 0 || *ep != '\0')
1332490Sjkh			errx(1, "denominator is not valid.");
134181409Sache		if (random_exit && denom > 256)
135181409Sache			errx(1, "denominator must be <= 256 for random exit.");
1362490Sjkh		break;
1372490Sjkh	default:
1388856Srgrimes		usage();
1392490Sjkh		/* NOTREACHED */
1402490Sjkh	}
1412490Sjkh
14226627Sache	srandomdev();
1432490Sjkh
1442490Sjkh	/*
1452490Sjkh	 * Act as a filter, randomly choosing lines of the standard input
1462490Sjkh	 * to write to the standard output.
1472490Sjkh	 */
1482490Sjkh	if (unbuffer_output)
1492490Sjkh		setbuf(stdout, NULL);
1508856Srgrimes
1512490Sjkh	/*
152110723Sseanc	 * Act as a filter, randomizing lines read in from a given file
153110723Sseanc	 * descriptor and write the output to standard output.
154110723Sseanc	 */
155110723Sseanc	if (randomize_lines) {
156110723Sseanc		if ((fd = open(filename, O_RDONLY, 0)) < 0)
157110928Sseanc			err(1, "%s", filename);
158110723Sseanc		ret = randomize_fd(fd, random_type, unique_output, denom);
159110723Sseanc		if (!random_exit)
160110723Sseanc			return(ret);
161110723Sseanc	}
162110723Sseanc
163110723Sseanc	/* Compute a random exit status between 0 and denom - 1. */
164110723Sseanc	if (random_exit)
165181527Sache		return (int)(denom * random() / RANDOM_MAX_PLUS1);
166110723Sseanc
167110723Sseanc	/*
1682490Sjkh	 * Select whether to print the first line.  (Prime the pump.)
1692490Sjkh	 * We find a random number between 0 and denom - 1 and, if it's
1702490Sjkh	 * 0 (which has a 1 / denom chance of being true), we select the
1712490Sjkh	 * line.
1722490Sjkh	 */
173181527Sache	selected = (int)(denom * random() / RANDOM_MAX_PLUS1) == 0;
1742490Sjkh	while ((ch = getchar()) != EOF) {
1752490Sjkh		if (selected)
1762490Sjkh			(void)putchar(ch);
1772490Sjkh		if (ch == '\n') {
1782490Sjkh			/* End of that line.  See if we got an error. */
1792490Sjkh			if (ferror(stdout))
1802490Sjkh				err(2, "stdout");
1812490Sjkh
1822490Sjkh			/* Now see if the next line is to be printed. */
183181615Sache			selected = (int)(denom * random() /
184181615Sache				RANDOM_MAX_PLUS1) == 0;
1852490Sjkh		}
1862490Sjkh	}
1872490Sjkh	if (ferror(stdin))
1882490Sjkh		err(2, "stdin");
1892490Sjkh	exit (0);
1902490Sjkh}
1912490Sjkh
192110928Sseancstatic void
193110928Sseancusage(void)
1942490Sjkh{
1952490Sjkh
196141581Sru	fprintf(stderr, "usage: random [-elrUuw] [-f filename] [denominator]\n");
1972490Sjkh	exit(1);
1982490Sjkh}
199