random.c revision 54482
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
372490Sjkh#ifndef lint
3853920Sbillfstatic const char copyright[] =
392490Sjkh"@(#) Copyright (c) 1994\n\
402490Sjkh	The Regents of the University of California.  All rights reserved.\n";
412490Sjkh#endif /* not lint */
422490Sjkh
432490Sjkh#ifndef lint
4453920Sbillf#if 0
452490Sjkhstatic char sccsid[] = "@(#)random.c	8.5 (Berkeley) 4/5/94";
4653920Sbillf#endif
4753920Sbillfstatic const char rcsid[] =
4853920Sbillf "$FreeBSD: head/games/random/random.c 54482 1999-12-12 06:30:46Z billf $";
492490Sjkh#endif /* not lint */
502490Sjkh
512490Sjkh#include <sys/types.h>
522490Sjkh
532490Sjkh#include <err.h>
542490Sjkh#include <errno.h>
556160Sbde#include <limits.h>
562490Sjkh#include <stdio.h>
572490Sjkh#include <stdlib.h>
582490Sjkh#include <time.h>
592490Sjkh#include <unistd.h>
602490Sjkh
612490Sjkhvoid usage __P((void));
622490Sjkh
632490Sjkhint
642490Sjkhmain(argc, argv)
652490Sjkh	int argc;
662490Sjkh	char *argv[];
672490Sjkh{
682490Sjkh	double denom;
692490Sjkh	int ch, random_exit, selected, unbuffer_output;
702490Sjkh	char *ep;
712490Sjkh
722490Sjkh	random_exit = unbuffer_output = 0;
7354482Sbillf	denom = 0;
7433937Sjkh	while ((ch = getopt(argc, argv, "er")) != -1)
752490Sjkh		switch (ch) {
762490Sjkh		case 'e':
772490Sjkh			random_exit = 1;
782490Sjkh			break;
792490Sjkh		case 'r':
802490Sjkh			unbuffer_output = 1;
812490Sjkh			break;
822490Sjkh		default:
832490Sjkh		case '?':
842490Sjkh			usage();
852490Sjkh			/* NOTREACHED */
862490Sjkh		}
872490Sjkh
882490Sjkh	argc -= optind;
892490Sjkh	argv += optind;
902490Sjkh
912490Sjkh	switch (argc) {
922490Sjkh	case 0:
932490Sjkh		denom = 2;
942490Sjkh		break;
952490Sjkh	case 1:
962490Sjkh		errno = 0;
972490Sjkh		denom = strtod(*argv, &ep);
982490Sjkh		if (errno == ERANGE)
992490Sjkh			err(1, "%s", *argv);
10024420Sache		if (denom <= 0 || *ep != '\0')
1012490Sjkh			errx(1, "denominator is not valid.");
10224420Sache		if (random_exit && denom > 255)
10324420Sache			errx(1, "denominator must be <= 255 for random exit.");
1042490Sjkh		break;
1052490Sjkh	default:
1068856Srgrimes		usage();
1072490Sjkh		/* NOTREACHED */
1082490Sjkh	}
1092490Sjkh
11026627Sache	srandomdev();
1112490Sjkh
1122490Sjkh	/* Compute a random exit status between 0 and denom - 1. */
1132490Sjkh	if (random_exit)
1142490Sjkh		return ((denom * random()) / LONG_MAX);
1152490Sjkh
1162490Sjkh	/*
1172490Sjkh	 * Act as a filter, randomly choosing lines of the standard input
1182490Sjkh	 * to write to the standard output.
1192490Sjkh	 */
1202490Sjkh	if (unbuffer_output)
1212490Sjkh		setbuf(stdout, NULL);
1228856Srgrimes
1232490Sjkh	/*
1242490Sjkh	 * Select whether to print the first line.  (Prime the pump.)
1252490Sjkh	 * We find a random number between 0 and denom - 1 and, if it's
1262490Sjkh	 * 0 (which has a 1 / denom chance of being true), we select the
1272490Sjkh	 * line.
1282490Sjkh	 */
1292490Sjkh	selected = (int)(denom * random() / LONG_MAX) == 0;
1302490Sjkh	while ((ch = getchar()) != EOF) {
1312490Sjkh		if (selected)
1322490Sjkh			(void)putchar(ch);
1332490Sjkh		if (ch == '\n') {
1342490Sjkh			/* End of that line.  See if we got an error. */
1352490Sjkh			if (ferror(stdout))
1362490Sjkh				err(2, "stdout");
1372490Sjkh
1382490Sjkh			/* Now see if the next line is to be printed. */
1392490Sjkh			selected = (int)(denom * random() / LONG_MAX) == 0;
1402490Sjkh		}
1412490Sjkh	}
1422490Sjkh	if (ferror(stdin))
1432490Sjkh		err(2, "stdin");
1442490Sjkh	exit (0);
1452490Sjkh}
1462490Sjkh
1472490Sjkhvoid
1482490Sjkhusage()
1492490Sjkh{
1502490Sjkh
1512490Sjkh	(void)fprintf(stderr, "usage: random [-er] [denominator]\n");
1522490Sjkh	exit(1);
1532490Sjkh}
154