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.
16203932Simp * 3. Neither the name of the University nor the names of its contributors
172490Sjkh *    may be used to endorse or promote products derived from this software
182490Sjkh *    without specific prior written permission.
192490Sjkh *
202490Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
212490Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
222490Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
232490Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
242490Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
252490Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
262490Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
272490Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
282490Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
292490Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
302490Sjkh * SUCH DAMAGE.
312490Sjkh */
322490Sjkh
33114725Sobrien#if 0
342490Sjkh#ifndef lint
3553920Sbillfstatic const char copyright[] =
362490Sjkh"@(#) Copyright (c) 1994\n\
372490Sjkh	The Regents of the University of California.  All rights reserved.\n";
382490Sjkh#endif /* not lint */
392490Sjkh
402490Sjkh#ifndef lint
41110928Sseancstatic const char sccsid[] = "@(#)random.c	8.5 (Berkeley) 4/5/94";
42114725Sobrien#endif /* not lint */
4353920Sbillf#endif
44110928Sseanc#include <sys/cdefs.h>
45110928Sseanc__FBSDID("$FreeBSD$");
46110928Sseanc
472490Sjkh#include <sys/types.h>
482490Sjkh
492490Sjkh#include <err.h>
502490Sjkh#include <errno.h>
51110723Sseanc#include <fcntl.h>
526160Sbde#include <limits.h>
53157758Sache#include <locale.h>
542490Sjkh#include <stdio.h>
552490Sjkh#include <stdlib.h>
56110928Sseanc#include <string.h>
572490Sjkh#include <time.h>
582490Sjkh#include <unistd.h>
59110928Sseanc
60110723Sseanc#include "randomize_fd.h"
612490Sjkh
62110928Sseancstatic void usage(void);
632490Sjkh
642490Sjkhint
65110928Sseancmain(int argc, char *argv[])
662490Sjkh{
672490Sjkh	double denom;
68110723Sseanc	int ch, fd, random_exit, randomize_lines, random_type, ret,
69110723Sseanc		selected, unique_output, unbuffer_output;
70136090Sstefanf	char *ep;
71136090Sstefanf	const char *filename;
722490Sjkh
7354482Sbillf	denom = 0;
74136090Sstefanf	filename = "/dev/fd/0";
75110723Sseanc	random_type = RANDOM_TYPE_UNSET;
76209157Suqs	random_exit = randomize_lines = unbuffer_output = 0;
77110723Sseanc	unique_output = 1;
78157758Sache
79157758Sache	(void)setlocale(LC_CTYPE, "");
80157758Sache
81110723Sseanc	while ((ch = getopt(argc, argv, "ef:hlruUw")) != -1)
822490Sjkh		switch (ch) {
832490Sjkh		case 'e':
842490Sjkh			random_exit = 1;
852490Sjkh			break;
86110723Sseanc		case 'f':
87110723Sseanc			randomize_lines = 1;
88136090Sstefanf			if (strcmp(optarg, "-") != 0)
89110723Sseanc				filename = optarg;
90110723Sseanc			break;
91110723Sseanc		case 'l':
92110723Sseanc			randomize_lines = 1;
93110723Sseanc			random_type = RANDOM_TYPE_LINES;
94110723Sseanc			break;
952490Sjkh		case 'r':
962490Sjkh			unbuffer_output = 1;
972490Sjkh			break;
98110723Sseanc		case 'u':
99110723Sseanc			randomize_lines = 1;
100110723Sseanc			unique_output = 1;
101110723Sseanc			break;
102110723Sseanc		case 'U':
103110723Sseanc			randomize_lines = 1;
104110723Sseanc			unique_output = 0;
105110723Sseanc			break;
106110723Sseanc		case 'w':
107110723Sseanc			randomize_lines = 1;
108110723Sseanc			random_type = RANDOM_TYPE_WORDS;
109110723Sseanc			break;
1102490Sjkh		default:
1112490Sjkh		case '?':
1122490Sjkh			usage();
1132490Sjkh			/* NOTREACHED */
1142490Sjkh		}
1152490Sjkh
1162490Sjkh	argc -= optind;
1172490Sjkh	argv += optind;
1182490Sjkh
1192490Sjkh	switch (argc) {
1202490Sjkh	case 0:
121110723Sseanc		denom = (randomize_lines ? 1 : 2);
1222490Sjkh		break;
1232490Sjkh	case 1:
1242490Sjkh		errno = 0;
1252490Sjkh		denom = strtod(*argv, &ep);
1262490Sjkh		if (errno == ERANGE)
1272490Sjkh			err(1, "%s", *argv);
12824420Sache		if (denom <= 0 || *ep != '\0')
1292490Sjkh			errx(1, "denominator is not valid.");
130181409Sache		if (random_exit && denom > 256)
131181409Sache			errx(1, "denominator must be <= 256 for random exit.");
1322490Sjkh		break;
1332490Sjkh	default:
1348856Srgrimes		usage();
1352490Sjkh		/* NOTREACHED */
1362490Sjkh	}
1372490Sjkh
13826627Sache	srandomdev();
1392490Sjkh
1402490Sjkh	/*
1412490Sjkh	 * Act as a filter, randomly choosing lines of the standard input
1422490Sjkh	 * to write to the standard output.
1432490Sjkh	 */
1442490Sjkh	if (unbuffer_output)
1452490Sjkh		setbuf(stdout, NULL);
1468856Srgrimes
1472490Sjkh	/*
148110723Sseanc	 * Act as a filter, randomizing lines read in from a given file
149110723Sseanc	 * descriptor and write the output to standard output.
150110723Sseanc	 */
151110723Sseanc	if (randomize_lines) {
152110723Sseanc		if ((fd = open(filename, O_RDONLY, 0)) < 0)
153110928Sseanc			err(1, "%s", filename);
154110723Sseanc		ret = randomize_fd(fd, random_type, unique_output, denom);
155110723Sseanc		if (!random_exit)
156110723Sseanc			return(ret);
157110723Sseanc	}
158110723Sseanc
159110723Sseanc	/* Compute a random exit status between 0 and denom - 1. */
160110723Sseanc	if (random_exit)
161181527Sache		return (int)(denom * random() / RANDOM_MAX_PLUS1);
162110723Sseanc
163110723Sseanc	/*
1642490Sjkh	 * Select whether to print the first line.  (Prime the pump.)
1652490Sjkh	 * We find a random number between 0 and denom - 1 and, if it's
1662490Sjkh	 * 0 (which has a 1 / denom chance of being true), we select the
1672490Sjkh	 * line.
1682490Sjkh	 */
169181527Sache	selected = (int)(denom * random() / RANDOM_MAX_PLUS1) == 0;
1702490Sjkh	while ((ch = getchar()) != EOF) {
1712490Sjkh		if (selected)
1722490Sjkh			(void)putchar(ch);
1732490Sjkh		if (ch == '\n') {
1742490Sjkh			/* End of that line.  See if we got an error. */
1752490Sjkh			if (ferror(stdout))
1762490Sjkh				err(2, "stdout");
1772490Sjkh
1782490Sjkh			/* Now see if the next line is to be printed. */
179181615Sache			selected = (int)(denom * random() /
180181615Sache				RANDOM_MAX_PLUS1) == 0;
1812490Sjkh		}
1822490Sjkh	}
1832490Sjkh	if (ferror(stdin))
1842490Sjkh		err(2, "stdin");
1852490Sjkh	exit (0);
1862490Sjkh}
1872490Sjkh
188110928Sseancstatic void
189110928Sseancusage(void)
1902490Sjkh{
1912490Sjkh
192141581Sru	fprintf(stderr, "usage: random [-elrUuw] [-f filename] [denominator]\n");
1932490Sjkh	exit(1);
1942490Sjkh}
195