2021-01-19 21:58:55 +00:00
/*
* Copyright ( c ) 2021 , Ben Wiederhake < BenWiederhake . GitHub @ gmx . de >
2022-11-24 17:10:47 +00:00
* Copyright ( c ) 2022 , Eli Youngs < eli . m . youngs @ gmail . com >
2021-01-19 21:58:55 +00:00
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2021-01-19 21:58:55 +00:00
*/
2021-05-14 15:17:26 +00:00
# include <AK/Random.h>
2021-01-19 21:58:55 +00:00
# include <AK/Vector.h>
2022-11-24 17:10:47 +00:00
# include <LibCore/ArgsParser.h>
2023-02-09 02:02:46 +00:00
# include <LibCore/File.h>
2022-01-20 20:12:35 +00:00
# include <LibCore/System.h>
# include <LibMain/Main.h>
2021-01-19 21:58:55 +00:00
2022-11-24 17:10:47 +00:00
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
2021-01-19 21:58:55 +00:00
{
2022-11-24 17:10:47 +00:00
TRY ( Core : : System : : pledge ( " stdio rpath " ) ) ;
Core : : ArgsParser args_parser ;
StringView path ;
2022-11-29 00:23:34 +00:00
Optional < size_t > head_count ;
2022-11-24 18:43:35 +00:00
bool is_zero_terminated = false ;
2023-05-16 19:59:15 +00:00
bool allow_repeats = false ;
2022-11-24 17:10:47 +00:00
args_parser . add_positional_argument ( path , " File " , " file " , Core : : ArgsParser : : Required : : No ) ;
2022-11-29 00:23:34 +00:00
args_parser . add_option ( head_count , " Output at most \" count \" lines " , " head-count " , ' n ' , " count " ) ;
2023-05-16 19:59:15 +00:00
args_parser . add_option ( allow_repeats , " Pick lines at random rather than shuffling. The program will continue indefinitely if no `-n` option is specified " , " repeat " , ' r ' ) ;
2022-11-24 18:43:35 +00:00
args_parser . add_option ( is_zero_terminated , " Split input on \\ 0, not newline " , " zero-terminated " , ' z ' ) ;
2022-11-24 17:10:47 +00:00
args_parser . parse ( arguments ) ;
2023-02-09 02:02:46 +00:00
auto file = TRY ( Core : : File : : open_file_or_standard_stream ( path , Core : : File : : OpenMode : : Read ) ) ;
2022-12-11 16:49:00 +00:00
ByteBuffer buffer = TRY ( file - > read_until_eof ( ) ) ;
2022-11-24 17:10:47 +00:00
2023-05-16 19:59:15 +00:00
u8 delimiter = is_zero_terminated ? ' \0 ' : ' \n ' ;
2022-11-24 17:10:47 +00:00
Vector < Bytes > lines ;
auto bytes = buffer . span ( ) ;
size_t line_start = 0 ;
size_t line_length = 0 ;
for ( size_t i = 0 ; i < bytes . size ( ) ; + + i ) {
2023-05-16 19:59:15 +00:00
if ( bytes [ i ] = = delimiter ) {
2022-11-24 17:10:47 +00:00
lines . append ( bytes . slice ( line_start , line_length ) ) ;
line_start = i + 1 ;
line_length = 0 ;
} else {
+ + line_length ;
2021-01-19 21:58:55 +00:00
}
}
2022-11-24 17:10:47 +00:00
if ( line_length > 0 ) {
lines . append ( bytes . slice ( line_start ) ) ;
}
2021-01-19 21:58:55 +00:00
2021-10-13 23:58:48 +00:00
if ( lines . is_empty ( ) )
return 0 ;
2023-05-16 19:59:15 +00:00
Array < u8 , 1 > delimiter_bytes { delimiter } ;
if ( allow_repeats ) {
for ( size_t line_count = 0 ; ! head_count . has_value ( ) | | line_count < head_count . value ( ) ; + + line_count ) {
size_t i = get_random_uniform ( lines . size ( ) ) ;
out ( lines . at ( i ) ) ;
out ( delimiter_bytes ) ;
}
} else {
shuffle ( lines ) ;
for ( size_t i = 0 ; i < min ( head_count . value_or ( lines . size ( ) ) , lines . size ( ) ) ; + + i ) {
out ( lines . at ( i ) ) ;
out ( delimiter_bytes ) ;
}
2021-01-19 21:58:55 +00:00
}
return 0 ;
}