"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 }