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