@@ -8,7 +8,6 @@ use coreutils::validation;
88use itertools:: Itertools as _;
99use std:: cmp;
1010use std:: ffi:: OsString ;
11- use std:: io:: { self , Write } ;
1211use std:: process;
1312use uucore:: Args ;
1413
@@ -49,13 +48,9 @@ fn usage<T>(utils: &UtilityMap<T>, name: &str) {
4948/// 'my_own_directory_service_ls' as long as the last letters match the utility.
5049/// * coreutils arg: --list, --version, -V, --help, -h (or shortened long versions): \
5150/// Output information about coreutils itself. \
52- /// Multiple of these arguments, output limited to one, with help > version > list.
5351/// * util name and any number of arguments: \
5452/// Will get passed on to the selected utility. \
5553/// Error if util name is not recognized.
56- /// * --help or -h and a following util name: \
57- /// Output help for that specific utility. \
58- /// So 'coreutils sum --help' is the same as 'coreutils --help sum'.
5954#[ allow( clippy:: cognitive_complexity) ]
6055fn main ( ) {
6156 uucore:: panic:: mute_sigpipe_panic ( ) ;
@@ -86,59 +81,49 @@ fn main() {
8681 validation:: not_found ( & OsString :: from ( binary_as_util) ) ;
8782 } ;
8883
89- // 0th argument equals util name?
84+ // 0th/1st argument equals util name?
9085 if let Some ( util_os) = util_name {
9186 let Some ( util) = util_os. to_str ( ) else {
87+ // Not UTF-8
9288 validation:: not_found ( & util_os)
9389 } ;
9490
95- #[ allow( clippy:: single_match_else) ]
96- match utils. get ( util) {
97- Some ( & ( uumain, _) ) => {
98- // TODO: plug the deactivation of the translation
99- // and load the English strings directly at compilation time in the
100- // binary to avoid the load of the flt
101- // Could be something like:
102- // #[cfg(not(feature = "only_english"))]
103- validation:: setup_localization_or_exit ( util) ;
104- process:: exit ( uumain ( vec ! [ util_os] . into_iter ( ) . chain ( args) ) ) ;
105- }
106- None => {
107- let ( option, help_util) = find_dominant_option ( & util_os, & mut args) ;
108- match option {
109- SelectedOption :: Help => match help_util {
110- // see if they want help on a specific util and if it is valid
111- Some ( u_os) => match utils. get ( & u_os. to_string_lossy ( ) ) {
112- Some ( & ( uumain, _) ) => {
113- let code = uumain (
114- vec ! [ u_os, OsString :: from( "--help" ) ]
115- . into_iter ( )
116- // Function requires a chain like in the Some case, but
117- // the args are discarded as clap returns help immediately.
118- . chain ( args) ,
119- ) ;
120- io:: stdout ( ) . flush ( ) . expect ( "could not flush stdout" ) ;
121- process:: exit ( code) ;
122- }
123- None => validation:: not_found ( & u_os) ,
124- } ,
125- // show coreutils help
126- None => usage ( & utils, binary_as_util) ,
127- } ,
128- SelectedOption :: Version => {
129- println ! ( "{binary_as_util} {VERSION} (multi-call binary)" ) ;
130- }
131- SelectedOption :: List => {
132- let utils: Vec < _ > = utils. keys ( ) . collect ( ) ;
133- for util in utils {
134- println ! ( "{util}" ) ;
135- }
136- }
137- SelectedOption :: Unrecognized ( arg) => {
138- // Argument looks like an option but wasn't recognized
139- validation:: unrecognized_option ( binary_as_util, & arg) ;
140- }
91+ // Util in known list?
92+ if let Some ( & ( uumain, _) ) = utils. get ( util) {
93+ // TODO: plug the deactivation of the translation
94+ // and load the English strings directly at compilation time in the
95+ // binary to avoid the load of the flt
96+ // Could be something like:
97+ // #[cfg(not(feature = "only_english"))]
98+ validation:: setup_localization_or_exit ( util) ;
99+ process:: exit ( uumain ( vec ! [ util_os] . into_iter ( ) . chain ( args) ) ) ;
100+ } else {
101+ let l = util. len ( ) ;
102+ // GNU coreutils --help string shows help for coreutils
103+ if util == "-h" || ( l <= 6 && util[ 0 ..l] == "--help" [ 0 ..l] ) {
104+ usage ( & utils, binary_as_util) ;
105+ process:: exit ( 0 ) ;
106+ // GNU coreutils --list string shows available utilities as list
107+ } else if l <= 6 && util[ 0 ..l] == "--list" [ 0 ..l] {
108+ // If --help is also present, show usage instead of list
109+ if args. any ( |arg| arg == "--help" || arg == "-h" ) {
110+ usage ( & utils, binary_as_util) ;
111+ process:: exit ( 0 ) ;
112+ }
113+ let utils: Vec < _ > = utils. keys ( ) . collect ( ) ;
114+ for util in utils {
115+ println ! ( "{util}" ) ;
141116 }
117+ process:: exit ( 0 ) ;
118+ // GNU coreutils --version string shows version
119+ } else if util == "-V" || ( l <= 9 && util[ 0 ..l] == "--version" [ 0 ..l] ) {
120+ println ! ( "{binary_as_util} {VERSION} (multi-call binary)" ) ;
121+ process:: exit ( 0 ) ;
122+ } else if util. starts_with ( '-' ) {
123+ // Argument looks like an option but wasn't recognized
124+ validation:: unrecognized_option ( binary_as_util, & util_os) ;
125+ } else {
126+ validation:: not_found ( & util_os) ;
142127 }
143128 }
144129 } else {
@@ -147,91 +132,3 @@ fn main() {
147132 process:: exit ( 0 ) ;
148133 }
149134}
150-
151- /// All defined coreutils options.
152- // Important: when changing then adapt also [identify_option_from_partial_text]
153- // as it works with the indices of this array.
154- const COREUTILS_OPTIONS : [ & str ; 5 ] = [ "--help" , "--list" , "--version" , "-h" , "-V" ] ;
155-
156- /// The dominant selected option.
157- #[ derive( Debug , Clone , PartialEq ) ]
158- enum SelectedOption {
159- Help ,
160- Version ,
161- List ,
162- Unrecognized ( OsString ) ,
163- }
164-
165- /// Coreutils only accepts one single option,
166- /// if multiple are given, use the most dominant one.
167- ///
168- /// Help > Version > List (e.g. 'coreutils --list --version' will return version)
169- /// Unrecognized will return immediately.
170- ///
171- /// # Returns
172- /// (SelectedOption, Util for help request, if any)
173- fn find_dominant_option (
174- first_arg : & OsString ,
175- args : & mut impl Iterator < Item = OsString > ,
176- ) -> ( SelectedOption , Option < OsString > ) {
177- let mut sel = identify_option_from_partial_text ( first_arg) ;
178- match sel {
179- SelectedOption :: Help => return ( SelectedOption :: Help , args. next ( ) ) ,
180- SelectedOption :: Unrecognized ( _) => {
181- return ( sel, None ) ;
182- }
183- _ => { }
184- }
185- // check remaining options, allows multiple
186- while let Some ( arg) = args. next ( ) {
187- let so = identify_option_from_partial_text ( & arg) ;
188- match so {
189- // most dominant, return directly
190- SelectedOption :: Help => {
191- // if help is wanted, check if a tool was named
192- return ( so, args. next ( ) ) ;
193- }
194- // best after help, can be set directly
195- SelectedOption :: Version => sel = SelectedOption :: Version ,
196- SelectedOption :: List => {
197- if sel != SelectedOption :: Version {
198- sel = SelectedOption :: List ;
199- }
200- }
201- // unrecognized is not allowed
202- SelectedOption :: Unrecognized ( _) => {
203- return ( so, None ) ;
204- }
205- }
206- }
207-
208- ( sel, None )
209- }
210-
211- // Will identify one, SelectedOption::None cannot be returned.
212- fn identify_option_from_partial_text ( arg : & OsString ) -> SelectedOption {
213- let mut option = & arg. to_string_lossy ( ) [ ..] ;
214- if let Some ( p) = option. find ( '=' ) {
215- option = & option[ 0 ..p] ;
216- }
217- let l = option. len ( ) ;
218- let possible_opts: Vec < usize > = COREUTILS_OPTIONS
219- . iter ( )
220- . enumerate ( )
221- . filter ( |( _, it) | it. len ( ) >= l && & it[ 0 ..l] == option)
222- . map ( |( id, _) | id)
223- . collect ( ) ;
224-
225- match possible_opts. len ( ) {
226- // exactly one hit
227- 1 => match & possible_opts[ 0 ] {
228- // number represents index of [COREUTILS_OPTIONS]
229- 0 | 3 => SelectedOption :: Help ,
230- 1 => SelectedOption :: List ,
231- 2 | 4 => SelectedOption :: Version ,
232- _ => SelectedOption :: Help ,
233- } ,
234- // None or more hits. The latter can not happen with the allowed options.
235- _ => SelectedOption :: Unrecognized ( arg. clone ( ) ) ,
236- }
237- }
0 commit comments