/* rl - Select a random line from stdin or file. Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Arthur de Jong This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include #include #include #include #include #ifdef HAVE_GETOPT_H #include #else /* not HAVE_GETOPT_H */ #include #endif /* not HAVE_GETOPT_H */ #ifndef HAVE_GETOPT_LONG #include "getopt_long.h" #endif /* not HAVE_GETOPT_LONG */ #include "rl.h" #include "alloc.h" #include "buffer.h" #include "random.h" /* the name of the program */ static char *program_name; /* flag to indicate output */ int quiet=0; /* Option flags and variables */ static struct option const long_options[] = { {"count",required_argument,NULL,'c'}, {"reselect",no_argument,NULL,'r'}, {"output",required_argument,NULL,'o'}, {"delimiter",required_argument,NULL,'d'}, {"null",no_argument,NULL,'0'}, {"line-number",no_argument,NULL,'n'}, {"line-numbers",no_argument,NULL,'n'}, {"quiet",no_argument,NULL,'q'}, {"silent",no_argument,NULL,'q'}, {"help",no_argument,NULL,'h'}, {"version",no_argument,NULL,'V'}, {NULL,0,NULL,0} }; /* for adding options you should add to long_options[] (directly above) OPTION_STRING (directly below) display_usage() (below) main() (for the handling of the option) */ #define OPTION_STRING "c:ro:d:0nqhV" /* display usage information */ static void display_usage(FILE *fp) { fprintf(fp,_("Usage: %s [OPTION]... [FILE]...\n"),program_name); fprintf(fp,_("Randomize the lines of a file (or stdin).\n\n")); fprintf(fp,_(" -c, --count=N select N lines from the file\n")); fprintf(fp,_(" -r, --reselect lines may be selected multiple times\n")); fprintf(fp,_(" -o, --output=FILE\n" " send output to file\n")); fprintf(fp,_(" -d, --delimiter=DELIM\n" " specify line delimiter (one character)\n")); fprintf(fp,_(" -0, --null set line delimiter to null character\n" " (useful with find -print0)\n")); fprintf(fp,_(" -n, --line-number\n" " print line number with output lines\n")); fprintf(fp,_(" -q, --quiet, --silent\n" " do not output any errors or warnings\n")); fprintf(fp,_(" -h, --help display this help and exit\n")); fprintf(fp,_(" -V, --version output version information and exit\n")); } /* display a use --help notice */ static void display_tryhelp(FILE *fp) { fprintf(fp,_("Try `%s --help' for more information.\n"),program_name); } /* display version information */ static void display_version(FILE *fp) { fprintf(fp,"rl %s\n",VERSION); fprintf(fp,_("Written by Arthur de Jong.\n\n")); fprintf(fp,_("Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Arthur de Jong.\n" "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n")); } /* read the whole file and pick out count random lines and dump to out all arguments are assumed to be reasonable values any line has an equal chance of getting picked and lines may be selected multiple times lines are delimited by delim */ static void rl_withreplace(FILE *in,FILE *out,int count,char delim,int print_linenumbers) { struct buffer *lines; /* array of lines */ struct buffer current; /* currently read line */ int line=0; /* the number of the current line */ int i; /* counter for loops */ /* initialize buffers */ lines=xxmalloc(struct buffer,count); for (i=0;i0) { for (i=0;ilinenumber=line+1; line++; } /* check for read errors */ if (ferror(in)) { fprintf(stderr,_("%s: read error: %s\n"),program_name,strerror(errno)); exit(1); } /* randomize these lines */ for (i=0;ilinenumber=line; if (random_draw(count,line)) { i=random_below(count); /* swap current with result[i] */ t=result[i]; result[i]=current; current=t; } } /* check for read errors */ if (ferror(in)) { fprintf(stderr,_("%s: read error: %s\n"),program_name,strerror(errno)); exit(1); } } /* dump the result (if any lines were read) */ for (i=0;(ilinenumber); /* output line */ if ( fwrite(result[i]->buf,sizeof(char),result[i]->len,out)!=result[i]->len || ferror(out) ) { fprintf(stderr,_("%s: write error: %s\n"),program_name,strerror(errno)); exit(1); } } /* free the memory! */ if (t!=NULL) /* t accidentaly points to the last current */ { buffer_free(t); xfree(t); } for (i=0;(i=alloc) { alloc=alloc*2; /* *4/3 */ /* only slightly grow */ result=xxrealloc(result,int,alloc); lines=xxrealloc(lines,struct buffer,alloc); } /* find the end of the line */ for (j=i;(j=argc) { if (count<=0) rl_randomizefile(stdin,output,delim,print_linenumbers); else if (uniq) rl_withoutreplace(stdin,output,count,delim,print_linenumbers); else rl_withreplace(stdin,output,count,delim,print_linenumbers); } else { for (;optind