shuffle.c revision 1.1 1 /* $NetBSD: shuffle.c,v 1.1 1998/09/23 21:05:59 perry Exp $ */
2
3 /*
4 * Copyright (c) 1998
5 * Perry E. Metzger. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgment:
17 * This product includes software developed for the NetBSD Project
18 * by Perry E. Metzger.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 __RCSID("$NetBSD: shuffle.c,v 1.1 1998/09/23 21:05:59 perry Exp $");
37 #endif /* not lint */
38
39 #include <err.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sys/time.h>
45
46 char **global_inputbuf;
47 int global_inputlen;
48
49 /*
50 * enomem --
51 * die when out of memory.
52 */
53 void
54 enomem()
55 {
56 errx(2, "Cannot allocate memory.");
57 }
58
59 /*
60 * emalloc --
61 * malloc, but die on error.
62 */
63 void *
64 emalloc(len)
65 size_t len;
66 {
67 void *p;
68
69 if ((p = malloc(len)) == NULL)
70 enomem();
71 return(p);
72 }
73
74 /*
75 * ecalloc --
76 * calloc, but die on error.
77 */
78 void *
79 ecalloc(size_t nmemb, size_t size)
80 {
81 void *p;
82
83 if ((p = calloc(nmemb, size)) == NULL)
84 enomem();
85 return(p);
86 }
87
88
89 /*
90 * estrdup --
91 * strdup, but die on error.
92 */
93 char *
94 estrdup(const char *str)
95 {
96 char *p;
97
98 if ((p = strdup(str)) == NULL)
99 enomem();
100 return(p);
101 }
102
103 /*
104 * erealloc --
105 * realloc, but die on error.
106 */
107 void *
108 erealloc(ptr, size)
109 void *ptr;
110 size_t size;
111 {
112 if ((ptr = realloc(ptr, size)) == NULL)
113 enomem();
114 return(ptr);
115 }
116
117 int *get_shuffle(int t)
118 {
119 int *shuffle;
120 int i, j, k, temp;
121
122 shuffle = (int *)ecalloc(t, sizeof(int));
123
124 for (i = 0; i < t; i++)
125 shuffle[i] = i;
126
127 /*
128 * This algorithm taken from Knuth, Seminumerical Algorithms,
129 * page 139.
130 */
131
132 /* for (j = 0; j < t; j++) {
133 k = random()%t; */
134
135 for (j = t-1; j > 0 ; j--) {
136 k = random() % (j+1);
137 temp = shuffle[j];
138 shuffle[j] = shuffle[k];
139 shuffle[k] = temp;
140 }
141
142 return(shuffle);
143 }
144
145 void
146 usage(void)
147 {
148 errx(1, "usage: shuffle [-c arg ...] [-n number] [-p number] [file]");
149 }
150
151 void
152 swallow_input(FILE *input)
153 {
154 int insize;
155 int numlines;
156 char **inputbuf, buf[BUFSIZ];
157
158
159 insize = BUFSIZ;
160 numlines = 0;
161
162 inputbuf = emalloc(sizeof(char *) * insize);
163
164 while (fgets(buf, BUFSIZ, input) != NULL) {
165 inputbuf[numlines] = estrdup(buf);
166 numlines++;
167 if (numlines >= insize) {
168 insize *= 2;
169 inputbuf = erealloc(inputbuf,
170 (sizeof(char *) * insize));
171 }
172 }
173 inputbuf[numlines] = NULL;
174
175 global_inputbuf = inputbuf;
176 global_inputlen = numlines;
177
178 }
179
180 int
181 main(int argc, char *argv[])
182 {
183 extern char *optarg;
184 extern int optind;
185 int cflag, nflag, pflag, ch;
186 int *shuffle;
187 int i, p, t;
188 FILE *input;
189 struct timeval tv;
190
191 cflag = nflag = pflag = 0;
192 while ((ch = getopt(argc, argv, "cn:p:")) != -1) {
193 switch(ch) {
194 case 'c':
195 cflag = 1;
196 break;
197 case 'n':
198 if ((t = atoi(optarg)) <= 0)
199 errx(1, "%d: number is invalid\n", t);
200 nflag = 1;
201 break;
202 case 'p':
203 if ((p = atoi(optarg)) <= 0)
204 errx(1, "%d: number is invalid\n", p);
205 pflag = 1;
206 break;
207 case '?':
208 default:
209 usage();
210 }
211 }
212 argc -= optind;
213 argv += optind;
214
215 if ((cflag && nflag) || (nflag && (argc > 0)))
216 usage();
217
218 if (cflag)
219 t = argc;
220
221 if (!(cflag || nflag)) {
222
223 if (argc > 1)
224 usage();
225 if (argc == 1) {
226 if ((input = fopen(argv[0], "r")) == NULL)
227 err(1, "could not open %s", argv[0]);
228 }
229 else {
230 input = stdin;
231 }
232
233 swallow_input(input);
234 t = global_inputlen;
235 }
236
237 gettimeofday(&tv, NULL);
238 srandom(getpid() ^ ~getuid() ^ tv.tv_sec ^ tv.tv_usec);
239
240 shuffle = get_shuffle(t);
241
242 if (pflag) {
243 if (p > t)
244 errx(1, "-p specified more components than exist.");
245 t = p;
246 }
247
248 for (i = 0; i < t; i++) {
249 if (nflag)
250 printf("%d\n", shuffle[i]);
251 else if (cflag)
252 printf("%s\n", argv[shuffle[i]]);
253 else
254 printf("%s", global_inputbuf[shuffle[i]]);
255 }
256
257 return(0);
258 }
259