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. 16203932Simp * 3. Neither the name of the University nor the names of its contributors 172490Sjkh * may be used to endorse or promote products derived from this software 182490Sjkh * without specific prior written permission. 192490Sjkh * 202490Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 212490Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 222490Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 232490Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 242490Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 252490Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 262490Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 272490Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 282490Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 292490Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 302490Sjkh * SUCH DAMAGE. 312490Sjkh */ 322490Sjkh 33114725Sobrien#if 0 342490Sjkh#ifndef lint 3553920Sbillfstatic const char copyright[] = 362490Sjkh"@(#) Copyright (c) 1994\n\ 372490Sjkh The Regents of the University of California. All rights reserved.\n"; 382490Sjkh#endif /* not lint */ 392490Sjkh 402490Sjkh#ifndef lint 41110928Sseancstatic const char sccsid[] = "@(#)random.c 8.5 (Berkeley) 4/5/94"; 42114725Sobrien#endif /* not lint */ 4353920Sbillf#endif 44110928Sseanc#include <sys/cdefs.h> 45110928Sseanc__FBSDID("$FreeBSD$"); 46110928Sseanc 472490Sjkh#include <sys/types.h> 482490Sjkh 492490Sjkh#include <err.h> 502490Sjkh#include <errno.h> 51110723Sseanc#include <fcntl.h> 526160Sbde#include <limits.h> 53157758Sache#include <locale.h> 542490Sjkh#include <stdio.h> 552490Sjkh#include <stdlib.h> 56110928Sseanc#include <string.h> 572490Sjkh#include <time.h> 582490Sjkh#include <unistd.h> 59110928Sseanc 60110723Sseanc#include "randomize_fd.h" 612490Sjkh 62110928Sseancstatic void usage(void); 632490Sjkh 642490Sjkhint 65110928Sseancmain(int argc, char *argv[]) 662490Sjkh{ 672490Sjkh double denom; 68110723Sseanc int ch, fd, random_exit, randomize_lines, random_type, ret, 69110723Sseanc selected, unique_output, unbuffer_output; 70136090Sstefanf char *ep; 71136090Sstefanf const char *filename; 722490Sjkh 7354482Sbillf denom = 0; 74136090Sstefanf filename = "/dev/fd/0"; 75110723Sseanc random_type = RANDOM_TYPE_UNSET; 76209157Suqs random_exit = randomize_lines = unbuffer_output = 0; 77110723Sseanc unique_output = 1; 78157758Sache 79157758Sache (void)setlocale(LC_CTYPE, ""); 80157758Sache 81110723Sseanc while ((ch = getopt(argc, argv, "ef:hlruUw")) != -1) 822490Sjkh switch (ch) { 832490Sjkh case 'e': 842490Sjkh random_exit = 1; 852490Sjkh break; 86110723Sseanc case 'f': 87110723Sseanc randomize_lines = 1; 88136090Sstefanf if (strcmp(optarg, "-") != 0) 89110723Sseanc filename = optarg; 90110723Sseanc break; 91110723Sseanc case 'l': 92110723Sseanc randomize_lines = 1; 93110723Sseanc random_type = RANDOM_TYPE_LINES; 94110723Sseanc break; 952490Sjkh case 'r': 962490Sjkh unbuffer_output = 1; 972490Sjkh break; 98110723Sseanc case 'u': 99110723Sseanc randomize_lines = 1; 100110723Sseanc unique_output = 1; 101110723Sseanc break; 102110723Sseanc case 'U': 103110723Sseanc randomize_lines = 1; 104110723Sseanc unique_output = 0; 105110723Sseanc break; 106110723Sseanc case 'w': 107110723Sseanc randomize_lines = 1; 108110723Sseanc random_type = RANDOM_TYPE_WORDS; 109110723Sseanc break; 1102490Sjkh default: 1112490Sjkh case '?': 1122490Sjkh usage(); 1132490Sjkh /* NOTREACHED */ 1142490Sjkh } 1152490Sjkh 1162490Sjkh argc -= optind; 1172490Sjkh argv += optind; 1182490Sjkh 1192490Sjkh switch (argc) { 1202490Sjkh case 0: 121110723Sseanc denom = (randomize_lines ? 1 : 2); 1222490Sjkh break; 1232490Sjkh case 1: 1242490Sjkh errno = 0; 1252490Sjkh denom = strtod(*argv, &ep); 1262490Sjkh if (errno == ERANGE) 1272490Sjkh err(1, "%s", *argv); 12824420Sache if (denom <= 0 || *ep != '\0') 1292490Sjkh errx(1, "denominator is not valid."); 130181409Sache if (random_exit && denom > 256) 131181409Sache errx(1, "denominator must be <= 256 for random exit."); 1322490Sjkh break; 1332490Sjkh default: 1348856Srgrimes usage(); 1352490Sjkh /* NOTREACHED */ 1362490Sjkh } 1372490Sjkh 13826627Sache srandomdev(); 1392490Sjkh 1402490Sjkh /* 1412490Sjkh * Act as a filter, randomly choosing lines of the standard input 1422490Sjkh * to write to the standard output. 1432490Sjkh */ 1442490Sjkh if (unbuffer_output) 1452490Sjkh setbuf(stdout, NULL); 1468856Srgrimes 1472490Sjkh /* 148110723Sseanc * Act as a filter, randomizing lines read in from a given file 149110723Sseanc * descriptor and write the output to standard output. 150110723Sseanc */ 151110723Sseanc if (randomize_lines) { 152110723Sseanc if ((fd = open(filename, O_RDONLY, 0)) < 0) 153110928Sseanc err(1, "%s", filename); 154110723Sseanc ret = randomize_fd(fd, random_type, unique_output, denom); 155110723Sseanc if (!random_exit) 156110723Sseanc return(ret); 157110723Sseanc } 158110723Sseanc 159110723Sseanc /* Compute a random exit status between 0 and denom - 1. */ 160110723Sseanc if (random_exit) 161181527Sache return (int)(denom * random() / RANDOM_MAX_PLUS1); 162110723Sseanc 163110723Sseanc /* 1642490Sjkh * Select whether to print the first line. (Prime the pump.) 1652490Sjkh * We find a random number between 0 and denom - 1 and, if it's 1662490Sjkh * 0 (which has a 1 / denom chance of being true), we select the 1672490Sjkh * line. 1682490Sjkh */ 169181527Sache selected = (int)(denom * random() / RANDOM_MAX_PLUS1) == 0; 1702490Sjkh while ((ch = getchar()) != EOF) { 1712490Sjkh if (selected) 1722490Sjkh (void)putchar(ch); 1732490Sjkh if (ch == '\n') { 1742490Sjkh /* End of that line. See if we got an error. */ 1752490Sjkh if (ferror(stdout)) 1762490Sjkh err(2, "stdout"); 1772490Sjkh 1782490Sjkh /* Now see if the next line is to be printed. */ 179181615Sache selected = (int)(denom * random() / 180181615Sache RANDOM_MAX_PLUS1) == 0; 1812490Sjkh } 1822490Sjkh } 1832490Sjkh if (ferror(stdin)) 1842490Sjkh err(2, "stdin"); 1852490Sjkh exit (0); 1862490Sjkh} 1872490Sjkh 188110928Sseancstatic void 189110928Sseancusage(void) 1902490Sjkh{ 1912490Sjkh 192141581Sru fprintf(stderr, "usage: random [-elrUuw] [-f filename] [denominator]\n"); 1932490Sjkh exit(1); 1942490Sjkh} 195