random.c revision 110723
1150362Simp/*
2150362Simp * Copyright (c) 1994
3150362Simp *	The Regents of the University of California.  All rights reserved.
4150362Simp *
5150362Simp * This code is derived from software contributed to Berkeley by
6150362Simp * Guy Harris at Network Appliance Corp.
7150362Simp *
8150362Simp * Redistribution and use in source and binary forms, with or without
9150362Simp * modification, are permitted provided that the following conditions
10150362Simp * are met:
11150362Simp * 1. Redistributions of source code must retain the above copyright
12150362Simp *    notice, this list of conditions and the following disclaimer.
13150362Simp * 2. Redistributions in binary form must reproduce the above copyright
14150362Simp *    notice, this list of conditions and the following disclaimer in the
15150362Simp *    documentation and/or other materials provided with the distribution.
16150362Simp * 3. All advertising materials mentioning features or use of this software
17150362Simp *    must display the following acknowledgement:
18150362Simp *	This product includes software developed by the University of
19150362Simp *	California, Berkeley and its contributors.
20150362Simp * 4. Neither the name of the University nor the names of its contributors
21150362Simp *    may be used to endorse or promote products derived from this software
22150362Simp *    without specific prior written permission.
23150362Simp *
24150362Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25150362Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26150362Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27150362Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28150362Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29150362Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30150362Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31150362Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32150362Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33150362Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34150362Simp * SUCH DAMAGE.
35150362Simp */
36150362Simp
37150362Simp#ifndef lint
38150362Simpstatic const char copyright[] =
39150362Simp"@(#) Copyright (c) 1994\n\
40150362Simp	The Regents of the University of California.  All rights reserved.\n";
41150362Simp#endif /* not lint */
42150362Simp
43150362Simp#ifndef lint
44150362Simp#if 0
45150362Simpstatic char sccsid[] = "@(#)random.c	8.5 (Berkeley) 4/5/94";
46150362Simp#endif
47150362Simpstatic const char rcsid[] =
48150362Simp "$FreeBSD: head/games/random/random.c 110723 2003-02-11 19:32:18Z seanc $";
49150362Simp#endif /* not lint */
50150362Simp
51150362Simp#include <sys/types.h>
52150362Simp
53150362Simp#include <err.h>
54150362Simp#include <errno.h>
55150362Simp#include <fcntl.h>
56150362Simp#include <limits.h>
57150362Simp#include <stdio.h>
58150362Simp#include <stdlib.h>
59150362Simp#include <time.h>
60150362Simp#include <unistd.h>
61150362Simp#include "randomize_fd.h"
62150362Simp
63150362Simpvoid usage(void);
64150400Simp
65150400Simpint
66150400Simpmain(int argc, char **argv)
67150400Simp{
68150400Simp	double denom;
69150362Simp	int ch, fd, random_exit, randomize_lines, random_type, ret,
70150362Simp		selected, unique_output, unbuffer_output;
71150362Simp	char *ep, *filename;
72150362Simp
73150362Simp	denom = 0;
74150362Simp	filename = NULL;
75150362Simp	random_type = RANDOM_TYPE_UNSET;
76150400Simp	random_exit = randomize_lines = random_type = unbuffer_output = 0;
77150400Simp	unique_output = 1;
78150362Simp	while ((ch = getopt(argc, argv, "ef:hlruUw")) != -1)
79150362Simp		switch (ch) {
80150362Simp		case 'e':
81150362Simp			random_exit = 1;
82150362Simp			break;
83150362Simp		case 'f':
84150362Simp			randomize_lines = 1;
85150362Simp			if (!strcmp(optarg, "-"))
86150362Simp				filename = strdup("/dev/fd/0");
87150362Simp			else
88150362Simp				filename = optarg;
89150362Simp			break;
90150362Simp		case 'l':
91150362Simp			randomize_lines = 1;
92150362Simp			random_type = RANDOM_TYPE_LINES;
93150362Simp			break;
94150362Simp		case 'r':
95150362Simp			unbuffer_output = 1;
96150362Simp			break;
97150362Simp		case 'u':
98150432Simp			randomize_lines = 1;
99150362Simp			unique_output = 1;
100150362Simp			break;
101150362Simp		case 'U':
102150362Simp			randomize_lines = 1;
103150362Simp			unique_output = 0;
104150362Simp			break;
105150362Simp		case 'w':
106150362Simp			randomize_lines = 1;
107150362Simp			random_type = RANDOM_TYPE_WORDS;
108150362Simp			break;
109150362Simp		default:
110150362Simp		case '?':
111150362Simp			usage();
112150362Simp			/* NOTREACHED */
113150362Simp		}
114150362Simp
115150362Simp	argc -= optind;
116150362Simp	argv += optind;
117150362Simp
118150362Simp	switch (argc) {
119150362Simp	case 0:
120150362Simp		denom = (randomize_lines ? 1 : 2);
121150362Simp		break;
122150362Simp	case 1:
123150362Simp		errno = 0;
124150362Simp		denom = strtod(*argv, &ep);
125150362Simp		if (errno == ERANGE)
126150362Simp			err(1, "%s", *argv);
127150362Simp		if (denom <= 0 || *ep != '\0')
128150362Simp			errx(1, "denominator is not valid.");
129150362Simp		if (random_exit && denom > 255)
130150362Simp			errx(1, "denominator must be <= 255 for random exit.");
131150362Simp		break;
132150362Simp	default:
133150362Simp		usage();
134150362Simp		/* NOTREACHED */
135150362Simp	}
136150362Simp
137150362Simp	srandomdev();
138150362Simp
139150362Simp	/*
140150362Simp	 * Act as a filter, randomly choosing lines of the standard input
141150362Simp	 * to write to the standard output.
142150362Simp	 */
143150362Simp	if (unbuffer_output)
144150362Simp		setbuf(stdout, NULL);
145150362Simp
146150362Simp	/*
147150362Simp	 * Act as a filter, randomizing lines read in from a given file
148150362Simp	 * descriptor and write the output to standard output.
149150362Simp	 */
150150362Simp	if (randomize_lines) {
151150362Simp		if ((fd = open(filename, O_RDONLY, 0)) < 0)
152150362Simp			err(1, "%s", optarg);
153150362Simp		ret = randomize_fd(fd, random_type, unique_output, denom);
154150362Simp		if (!random_exit)
155150362Simp			return(ret);
156150362Simp	}
157150362Simp
158150362Simp	/* Compute a random exit status between 0 and denom - 1. */
159150362Simp	if (random_exit)
160150362Simp		return ((denom * random()) / LONG_MAX);
161150362Simp
162150362Simp	/*
163150362Simp	 * Select whether to print the first line.  (Prime the pump.)
164150362Simp	 * We find a random number between 0 and denom - 1 and, if it's
165150362Simp	 * 0 (which has a 1 / denom chance of being true), we select the
166150362Simp	 * line.
167150362Simp	 */
168150362Simp	selected = (int)(denom * random() / LONG_MAX) == 0;
169150362Simp	while ((ch = getchar()) != EOF) {
170150362Simp		if (selected)
171150362Simp			(void)putchar(ch);
172150362Simp		if (ch == '\n') {
173150362Simp			/* End of that line.  See if we got an error. */
174			if (ferror(stdout))
175				err(2, "stdout");
176
177			/* Now see if the next line is to be printed. */
178			selected = (int)(denom * random() / LONG_MAX) == 0;
179		}
180	}
181	if (ferror(stdin))
182		err(2, "stdin");
183	exit (0);
184}
185
186void
187usage()
188{
189
190	(void)fprintf(stderr, "usage: random [-elruUw] [-f filename] [denominator]\n");
191	exit(1);
192}
193