2 * Copyright (C) 2003 Sean Chittenden <seanc@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/types.h>
31 #include <sys/param.h>
41 #include "randomize_fd.h"
43 static struct rand_node
*rand_root
;
44 static struct rand_node
*rand_tail
;
46 static struct rand_node
*
47 rand_node_allocate(void)
51 n
= (struct rand_node
*)malloc(sizeof(struct rand_node
));
62 rand_node_free(struct rand_node
*n
)
73 rand_node_free_rec(struct rand_node
*n
)
77 rand_node_free_rec(n
->next
);
84 rand_node_append(struct rand_node
*n
)
86 if (rand_root
== NULL
)
87 rand_root
= rand_tail
= n
;
95 randomize_fd(int fd
, int type
, int unique
, double denom
)
99 u_long i
, j
, numnode
, selected
;
100 struct rand_node
*n
, *prev
;
101 int bufleft
, eof
, fndstr
, ret
;
105 rand_root
= rand_tail
= NULL
;
107 bufleft
= eof
= fndstr
= numnode
= ret
= 0;
109 if (type
== RANDOM_TYPE_UNSET
)
110 type
= RANDOM_TYPE_LINES
;
112 buflen
= sizeof(u_char
) * MAXBSIZE
;
113 buf
= (u_char
*)malloc(buflen
);
118 /* Check to see if we have bits in the buffer */
120 len
= read(fd
, buf
, buflen
);
126 } else if ((size_t)len
< buflen
)
127 buflen
= (size_t)len
;
132 /* Look for a newline */
133 for (i
= bufc
; i
<= buflen
&& bufleft
>= 0; i
++, bufleft
--) {
137 memmove(buf
, &buf
[bufc
], i
- bufc
);
140 len
= read(fd
, &buf
[i
], buflen
- i
);
146 } else if (len
< (ssize_t
)(buflen
- i
))
147 buflen
= i
+ (size_t)len
;
154 buf
= (u_char
*)realloc(buf
, buflen
);
159 len
= read(fd
, &buf
[i
], buflen
- i
);
165 } else if (len
< (ssize_t
)(buflen
- i
))
166 buflen
= i
+ (size_t)len
;
174 if ((type
== RANDOM_TYPE_LINES
&& buf
[i
] == '\n') ||
175 (type
== RANDOM_TYPE_WORDS
&& isspace(buf
[i
])) ||
176 (eof
&& i
== buflen
- 1)) {
178 if (numnode
== RANDOM_MAX_PLUS1
) {
180 err(1, "too many delimiters");
183 n
= rand_node_allocate();
185 slen
= i
- (u_long
)bufc
;
187 n
->cp
= (u_char
*)malloc(slen
+ 2);
191 memmove(n
->cp
, &buf
[bufc
], slen
);
192 n
->cp
[slen
] = buf
[i
];
193 n
->cp
[slen
+ 1] = '\0';
204 /* Necessary evil to compensate for files that don't end with a newline */
210 for (i
= numnode
; i
> 0; i
--) {
211 selected
= random() % numnode
;
213 for (j
= 0, prev
= n
= rand_root
; n
!= NULL
; j
++, prev
= n
, n
= n
->next
) {
218 if ((int)(denom
* random() /
219 RANDOM_MAX_PLUS1
) == 0) {
221 (int)n
->len
- 1, n
->cp
);
231 prev
->next
= n
->next
;
243 rand_node_free_rec(rand_root
);