"Fossies" - the Fresh Open Source Software Archive 
Member "littleutils-1.2.5/littleutils/randomize.c" (29 Oct 2021, 8888 Bytes) of package /linux/privat/littleutils-1.2.5.tar.lz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "randomize.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.2.4_vs_1.2.5.
1 /* randomize: Randomizes lines from a file or from stdin.
2
3 Copyright (C) 2004-2021 by Brian Lindholm.
4 This file is part of the littleutils utility set.
5
6 The randomize utility is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option) any
9 later version.
10
11 The randomize utility is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU General Public License along with
17 the littleutils. If not, see <https://www.gnu.org/licenses/>. */
18
19
20 #include <config.h>
21
22 #include <fcntl.h>
23 #ifdef HAVE_STDIO_H
24 # include <stdio.h>
25 #endif
26 #ifdef HAVE_STDLIB_H
27 # include <stdlib.h>
28 #endif
29 #ifdef HAVE_STRING_H
30 # include <string.h>
31 #endif
32 #ifdef HAVE_SYS_RANDOM_H
33 # include <sys/random.h>
34 #endif
35 #ifdef HAVE_SYS_STAT_H
36 # include <sys/stat.h>
37 #endif
38
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 # define OPTEND -1
42 #else
43 # define OPTEND EOF
44 #endif
45 #ifdef HAVE_GETOPT_H
46 # include <getopt.h>
47 #endif
48
49 #include "rand_funcs.h"
50
51 #ifdef __MINGW32__
52 extern int getopt (int argc, char * const *argv, const char *optstring);
53 extern char *optarg;
54 extern int optind;
55 #endif
56
57 #ifdef DJGPP
58 /* speed up stat command for DJGPP */
59 unsigned short _djstat_flags = 63;
60 #endif
61
62 #ifndef BLOCKSIZE
63 # define BLOCKSIZE 8192
64 #endif
65
66 #ifndef PATH_MAX
67 # define PATH_MAX 256
68 #endif
69
70
71 /* help function */
72
73 static void
74 help (FILE *where)
75 {
76 fprintf (where,
77 "randomize " PACKAGE_VERSION "\n"
78 "usage: randomize [-0/-z(ero_terminated)] [file...]\n");
79 }
80
81
82 /* read stdin into a buffer allocated here, returning number of bytes read */
83
84 static size_t
85 load_stdin (char **buffer, char delimiter)
86 {
87 char *tmp_buffer;
88 size_t buffer_size, last_read, size;
89
90 /* set up initial block */
91 buffer_size = BLOCKSIZE;
92 tmp_buffer = (char *) malloc (buffer_size * sizeof(char));
93 if (tmp_buffer == NULL)
94 {
95 fprintf (stderr, "randomize error: out of memory A!\n");
96 exit (4);
97 }
98
99 /* keep reading, doubling the memory allocation along the way if necessary */
100 size = 0;
101 while (!feof (stdin))
102 {
103 last_read = fread (&tmp_buffer[size], sizeof(char), BLOCKSIZE, stdin);
104 size += last_read * sizeof(char);
105 if ((!feof (stdin)) && ((size + BLOCKSIZE) >= buffer_size))
106 {
107 buffer_size *= 2;
108 tmp_buffer = realloc (tmp_buffer, buffer_size);
109 if (tmp_buffer == NULL)
110 {
111 fprintf (stderr, "randomize error: out of memory B!\n");
112 exit (4);
113 }
114 }
115 }
116
117 /* ensure that the last character of non-empty input is a delimiter
118 character, appending it if necessary */
119 if ((size > 0) && (tmp_buffer[size - 1] != delimiter))
120 {
121 if (size == buffer_size)
122 {
123 tmp_buffer = realloc (tmp_buffer, buffer_size + 1);
124 if (tmp_buffer == NULL)
125 {
126 fprintf (stderr, "randomize error: out of memory B!\n");
127 exit (4);
128 }
129 }
130 tmp_buffer[size] = delimiter;
131 size += 1;
132 }
133 *buffer = tmp_buffer;
134 return (size);
135 }
136
137
138 /* allocate memory for files function, returning a pointer to a buffer */
139
140 static void
141 prep_buffer (char **buffer, size_t size)
142 {
143 char *tmp_buffer;
144
145 tmp_buffer = (char *) malloc (size * sizeof(char));
146 if (tmp_buffer == NULL)
147 {
148 fprintf (stderr, "randomize error: out of memory C!\n");
149 exit (4);
150 }
151 *buffer = tmp_buffer;
152 }
153
154
155 /* read a file into a pre-allocated buffer, returning number of bytes read
156 from file */
157
158 static size_t
159 load_file (char *buffer, char *filename, size_t size, size_t index, char delimiter)
160 {
161 size_t qty_read;
162 FILE *input_file;
163
164 input_file = fopen (filename, "r");
165 if (input_file == NULL)
166 {
167 fprintf (stderr, "randomize error: can't open %s!\n", filename);
168 exit (3);
169 }
170
171 /* read in the file */
172 qty_read = fread (&buffer[index], sizeof(char), size, input_file);
173 if (qty_read != size)
174 {
175 fprintf (stderr, "randomize error: can't read all of %s!\n", filename);
176 exit (3);
177 }
178
179 /* ensure that the last character of non-empty input is a delimiter
180 character, appending it if necessary */
181 if (((index + size) > 0) && (buffer[index + size - 1] != delimiter))
182 {
183 buffer[index + size] = delimiter;
184 size += 1;
185 }
186 (void) fclose (input_file);
187 return (size);
188 }
189
190
191 /* scan buffer for substrings, returning arrays of pointers and lengths */
192
193 static void
194 scan_buffer (char *buffer, size_t **indices, size_t **lengths, size_t size,
195 size_t delimiter_qty, char delimiter)
196 {
197 size_t i, index, previous_end;
198 size_t *tmp_indices, *tmp_lengths;
199
200 /* allocate access arrays */
201 tmp_indices = (size_t *) malloc ((delimiter_qty + 1) * sizeof(size_t));
202 if (tmp_indices == NULL)
203 {
204 fprintf (stderr, "randomize error: out of memory D\n");
205 exit (4);
206 }
207 tmp_lengths = (size_t *) malloc ((delimiter_qty + 1) * sizeof(size_t));
208 if (tmp_lengths == NULL)
209 {
210 fprintf (stderr, "randomize error: out of memory E\n");
211 exit (4);
212 }
213
214 /* find first line */
215 index = 0;
216 tmp_indices[index] = 0;
217 i = 0;
218 while ((buffer[i] != delimiter) && (i < size))
219 i++;
220 tmp_lengths[index] = i;
221 previous_end = i;
222
223 /* find remaining lines */
224 for (i = previous_end + 1; i < size; i++)
225 if (buffer[i] == delimiter)
226 {
227 index++;
228 tmp_indices[index] = previous_end + 1;
229 tmp_lengths[index] = i - previous_end - 1;
230 previous_end = i;
231 }
232
233 /* sanity check */
234 if (index != (delimiter_qty - 1))
235 {
236 fprintf (stderr, "randomize error: count mismatch %u vs. %u!\n",
237 (unsigned int) index, (unsigned int) delimiter_qty - 1);
238 exit (3);
239 }
240 *indices = tmp_indices;
241 *lengths = tmp_lengths;
242 }
243
244
245 /* main program */
246
247 int
248 main (int argc, char *argv[])
249 {
250 char *buffer, delimiter, *filename;
251 int argn, opt;
252 size_t delimiter_qty, i, index, *indices, j, k, length, *lengths, size, sum;
253 struct stat file_stats;
254
255 /* parse options */
256 delimiter = '\n';
257 while ((opt = getopt (argc, argv, "0hz")) != OPTEND)
258 switch (opt)
259 {
260 case '0':
261 delimiter = '\0';
262 break;
263 case 'h':
264 help (stdout);
265 return (0);
266 case 'z':
267 delimiter = '\0';
268 break;
269 case '?':
270 help (stderr);
271 return (1);
272 }
273
274 /* read standard input or files into buffer */
275 if ((argc - optind) == 0)
276 size = load_stdin (&buffer, delimiter);
277 else
278 {
279 sum = 0;
280 for (argn = optind; argn < argc; argn++)
281 {
282 filename = argv[argn];
283 if (stat (filename, &file_stats))
284 {
285 fprintf (stderr,
286 "randomize error: can't determine size of %s\n", filename);
287 exit (1);
288 }
289 if (((file_stats.st_mode & S_IFDIR) != S_IFDIR) &&
290 ((file_stats.st_mode & S_IFREG) == S_IFREG))
291 sum += (size_t) file_stats.st_size + 1;
292 else
293 fprintf (stderr,
294 "randomize warning: skipping non-regular file %s \n", filename);
295 }
296 prep_buffer (&buffer, sum);
297 index = 0;
298 for (argn = optind; argn < argc; argn++)
299 {
300 filename = argv[argn];
301 (void) stat (filename, &file_stats);
302 if (((file_stats.st_mode & S_IFDIR) != S_IFDIR) &&
303 ((file_stats.st_mode & S_IFREG) == S_IFREG))
304 index += load_file (buffer, filename, (size_t) file_stats.st_size,
305 index, delimiter);
306 }
307 size = index;
308 }
309
310 if (size > 0)
311 {
312 /* count delimiters */
313 delimiter_qty = 0;
314 for (i = 0; i < size; i++)
315 if (buffer[i] == delimiter)
316 delimiter_qty++;
317
318 /* create access arrays for index and length */
319 scan_buffer (buffer, &indices, &lengths, size, delimiter_qty, delimiter);
320 rand_seed ();
321
322 /* shuffle the list twice */
323 for (k = 0; k < 2; k++)
324 for (i = 0; i < delimiter_qty; i++)
325 {
326 j = rand_int (delimiter_qty);
327 index = indices[i];
328 indices[i] = indices[j];
329 indices[j] = index;
330 length = lengths[i];
331 lengths[i] = lengths[j];
332 lengths[j] = length;
333 }
334
335 /* print the list using the randomized pointers */
336 for (i = 0; i < delimiter_qty; i++)
337 (void) fwrite (&buffer[indices[i]], sizeof(char), lengths[i] + 1,
338 stdout);
339
340 /* free up arrays */
341 free (lengths);
342 free (indices);
343 }
344
345 /* free up buffer */
346 free (buffer);
347
348 /* indicate successful finish */
349 return (0);
350 }