random.c revision 8856
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
382490Sjkhstatic 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
442490Sjkhstatic char sccsid[] = "@(#)random.c	8.5 (Berkeley) 4/5/94";
452490Sjkh#endif /* not lint */
462490Sjkh
472490Sjkh#include <sys/types.h>
482490Sjkh
492490Sjkh#include <err.h>
502490Sjkh#include <errno.h>
516160Sbde#include <limits.h>
522490Sjkh#include <stdio.h>
532490Sjkh#include <stdlib.h>
542490Sjkh#include <time.h>
552490Sjkh#include <unistd.h>
562490Sjkh
572490Sjkhvoid usage __P((void));
582490Sjkh
592490Sjkhint
602490Sjkhmain(argc, argv)
612490Sjkh	int argc;
622490Sjkh	char *argv[];
632490Sjkh{
642490Sjkh	extern int optind;
652490Sjkh	time_t now;
662490Sjkh	double denom;
672490Sjkh	int ch, random_exit, selected, unbuffer_output;
682490Sjkh	char *ep;
692490Sjkh
702490Sjkh	random_exit = unbuffer_output = 0;
712490Sjkh	while ((ch = getopt(argc, argv, "er")) != EOF)
722490Sjkh		switch (ch) {
732490Sjkh		case 'e':
742490Sjkh			random_exit = 1;
752490Sjkh			break;
762490Sjkh		case 'r':
772490Sjkh			unbuffer_output = 1;
782490Sjkh			break;
792490Sjkh		default:
802490Sjkh		case '?':
812490Sjkh			usage();
822490Sjkh			/* NOTREACHED */
832490Sjkh		}
842490Sjkh
852490Sjkh	argc -= optind;
862490Sjkh	argv += optind;
872490Sjkh
882490Sjkh	switch (argc) {
892490Sjkh	case 0:
902490Sjkh		denom = 2;
912490Sjkh		break;
922490Sjkh	case 1:
932490Sjkh		errno = 0;
942490Sjkh		denom = strtod(*argv, &ep);
952490Sjkh		if (errno == ERANGE)
962490Sjkh			err(1, "%s", *argv);
972490Sjkh		if (denom == 0 || *ep != '\0')
982490Sjkh			errx(1, "denominator is not valid.");
992490Sjkh		break;
1002490Sjkh	default:
1018856Srgrimes		usage();
1022490Sjkh		/* NOTREACHED */
1032490Sjkh	}
1042490Sjkh
1052490Sjkh	(void)time(&now);
1062490Sjkh	srandom((u_int)(now + getpid()));
1072490Sjkh
1082490Sjkh	/* Compute a random exit status between 0 and denom - 1. */
1092490Sjkh	if (random_exit)
1102490Sjkh		return ((denom * random()) / LONG_MAX);
1112490Sjkh
1122490Sjkh	/*
1132490Sjkh	 * Act as a filter, randomly choosing lines of the standard input
1142490Sjkh	 * to write to the standard output.
1152490Sjkh	 */
1162490Sjkh	if (unbuffer_output)
1172490Sjkh		setbuf(stdout, NULL);
1188856Srgrimes
1192490Sjkh	/*
1202490Sjkh	 * Select whether to print the first line.  (Prime the pump.)
1212490Sjkh	 * We find a random number between 0 and denom - 1 and, if it's
1222490Sjkh	 * 0 (which has a 1 / denom chance of being true), we select the
1232490Sjkh	 * line.
1242490Sjkh	 */
1252490Sjkh	selected = (int)(denom * random() / LONG_MAX) == 0;
1262490Sjkh	while ((ch = getchar()) != EOF) {
1272490Sjkh		if (selected)
1282490Sjkh			(void)putchar(ch);
1292490Sjkh		if (ch == '\n') {
1302490Sjkh			/* End of that line.  See if we got an error. */
1312490Sjkh			if (ferror(stdout))
1322490Sjkh				err(2, "stdout");
1332490Sjkh
1342490Sjkh			/* Now see if the next line is to be printed. */
1352490Sjkh			selected = (int)(denom * random() / LONG_MAX) == 0;
1362490Sjkh		}
1372490Sjkh	}
1382490Sjkh	if (ferror(stdin))
1392490Sjkh		err(2, "stdin");
1402490Sjkh	exit (0);
1412490Sjkh}
1422490Sjkh
1432490Sjkhvoid
1442490Sjkhusage()
1452490Sjkh{
1462490Sjkh
1472490Sjkh	(void)fprintf(stderr, "usage: random [-er] [denominator]\n");
1482490Sjkh	exit(1);
1492490Sjkh}
150