random.c revision 157758
1275988Sngie/* 2240116Smarcel * Copyright (c) 1994 3240116Smarcel * The Regents of the University of California. All rights reserved. 4240116Smarcel * 5240116Smarcel * This code is derived from software contributed to Berkeley by 6240116Smarcel * Guy Harris at Network Appliance Corp. 7240116Smarcel * 8240116Smarcel * Redistribution and use in source and binary forms, with or without 9240116Smarcel * modification, are permitted provided that the following conditions 10240116Smarcel * are met: 11240116Smarcel * 1. Redistributions of source code must retain the above copyright 12240116Smarcel * notice, this list of conditions and the following disclaimer. 13240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 14240116Smarcel * notice, this list of conditions and the following disclaimer in the 15240116Smarcel * documentation and/or other materials provided with the distribution. 16240116Smarcel * 3. All advertising materials mentioning features or use of this software 17240116Smarcel * must display the following acknowledgement: 18240116Smarcel * This product includes software developed by the University of 19240116Smarcel * California, Berkeley and its contributors. 20240116Smarcel * 4. Neither the name of the University nor the names of its contributors 21240116Smarcel * may be used to endorse or promote products derived from this software 22240116Smarcel * without specific prior written permission. 23240116Smarcel * 24275988Sngie * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25240116Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26240116Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27240116Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28240116Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30240116Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31240116Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32240116Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33240116Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34240116Smarcel * SUCH DAMAGE. 35240116Smarcel */ 36240116Smarcel 37240116Smarcel#if 0 38240116Smarcel#ifndef lint 39240116Smarcelstatic const char copyright[] = 40240116Smarcel"@(#) Copyright (c) 1994\n\ 41240116Smarcel The Regents of the University of California. All rights reserved.\n"; 42240116Smarcel#endif /* not lint */ 43240116Smarcel 44240116Smarcel#ifndef lint 45240116Smarcelstatic const char sccsid[] = "@(#)random.c 8.5 (Berkeley) 4/5/94"; 46240116Smarcel#endif /* not lint */ 47240116Smarcel#endif 48240116Smarcel#include <sys/cdefs.h> 49240116Smarcel__FBSDID("$FreeBSD: head/games/random/random.c 157758 2006-04-14 17:32:27Z ache $"); 50240116Smarcel 51240116Smarcel#include <sys/types.h> 52240116Smarcel 53240116Smarcel#include <err.h> 54240116Smarcel#include <errno.h> 55240116Smarcel#include <fcntl.h> 56240116Smarcel#include <limits.h> 57240116Smarcel#include <locale.h> 58240116Smarcel#include <stdio.h> 59240116Smarcel#include <stdlib.h> 60240116Smarcel#include <string.h> 61240116Smarcel#include <time.h> 62240116Smarcel#include <unistd.h> 63240116Smarcel 64240116Smarcel#include "randomize_fd.h" 65275988Sngie 66/* 67 * The random() function is defined to return values between 0 and 68 * 2^31 - 1 inclusive in random(3). 69 */ 70#define RANDOM_MAX 0x7fffffffL 71 72static void usage(void); 73 74int 75main(int argc, char *argv[]) 76{ 77 double denom; 78 int ch, fd, random_exit, randomize_lines, random_type, ret, 79 selected, unique_output, unbuffer_output; 80 char *ep; 81 const char *filename; 82 83 denom = 0; 84 filename = "/dev/fd/0"; 85 random_type = RANDOM_TYPE_UNSET; 86 random_exit = randomize_lines = random_type = unbuffer_output = 0; 87 unique_output = 1; 88 89 (void)setlocale(LC_CTYPE, ""); 90 91 while ((ch = getopt(argc, argv, "ef:hlruUw")) != -1) 92 switch (ch) { 93 case 'e': 94 random_exit = 1; 95 break; 96 case 'f': 97 randomize_lines = 1; 98 if (strcmp(optarg, "-") != 0) 99 filename = optarg; 100 break; 101 case 'l': 102 randomize_lines = 1; 103 random_type = RANDOM_TYPE_LINES; 104 break; 105 case 'r': 106 unbuffer_output = 1; 107 break; 108 case 'u': 109 randomize_lines = 1; 110 unique_output = 1; 111 break; 112 case 'U': 113 randomize_lines = 1; 114 unique_output = 0; 115 break; 116 case 'w': 117 randomize_lines = 1; 118 random_type = RANDOM_TYPE_WORDS; 119 break; 120 default: 121 case '?': 122 usage(); 123 /* NOTREACHED */ 124 } 125 126 argc -= optind; 127 argv += optind; 128 129 switch (argc) { 130 case 0: 131 denom = (randomize_lines ? 1 : 2); 132 break; 133 case 1: 134 errno = 0; 135 denom = strtod(*argv, &ep); 136 if (errno == ERANGE) 137 err(1, "%s", *argv); 138 if (denom <= 0 || *ep != '\0') 139 errx(1, "denominator is not valid."); 140 if (random_exit && denom > 255) 141 errx(1, "denominator must be <= 255 for random exit."); 142 break; 143 default: 144 usage(); 145 /* NOTREACHED */ 146 } 147 148 srandomdev(); 149 150 /* 151 * Act as a filter, randomly choosing lines of the standard input 152 * to write to the standard output. 153 */ 154 if (unbuffer_output) 155 setbuf(stdout, NULL); 156 157 /* 158 * Act as a filter, randomizing lines read in from a given file 159 * descriptor and write the output to standard output. 160 */ 161 if (randomize_lines) { 162 if ((fd = open(filename, O_RDONLY, 0)) < 0) 163 err(1, "%s", filename); 164 ret = randomize_fd(fd, random_type, unique_output, denom); 165 if (!random_exit) 166 return(ret); 167 } 168 169 /* Compute a random exit status between 0 and denom - 1. */ 170 if (random_exit) 171 return (int)((denom * random()) / RANDOM_MAX); 172 173 /* 174 * Select whether to print the first line. (Prime the pump.) 175 * We find a random number between 0 and denom - 1 and, if it's 176 * 0 (which has a 1 / denom chance of being true), we select the 177 * line. 178 */ 179 selected = (int)(denom * random() / RANDOM_MAX) == 0; 180 while ((ch = getchar()) != EOF) { 181 if (selected) 182 (void)putchar(ch); 183 if (ch == '\n') { 184 /* End of that line. See if we got an error. */ 185 if (ferror(stdout)) 186 err(2, "stdout"); 187 188 /* Now see if the next line is to be printed. */ 189 selected = (int)(denom * random() / RANDOM_MAX) == 0; 190 } 191 } 192 if (ferror(stdin)) 193 err(2, "stdin"); 194 exit (0); 195} 196 197static void 198usage(void) 199{ 200 201 fprintf(stderr, "usage: random [-elrUuw] [-f filename] [denominator]\n"); 202 exit(1); 203} 204