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