@@ -135,12 +135,62 @@ fn filetime_to_datetime(ft: &FileTime) -> Option<DateTime<Local>> {
135135 Some ( DateTime :: from_timestamp ( ft. unix_seconds ( ) , ft. nanoseconds ( ) ) ?. into ( ) )
136136}
137137
138+ /// Whether all characters in the string are digits.
139+ fn all_digits ( s : & str ) -> bool {
140+ s. as_bytes ( ) . iter ( ) . all ( u8:: is_ascii_digit)
141+ }
142+
143+ /// Convert a two-digit year string to the corresponding number.
144+ ///
145+ /// `s` must be of length two or more. The last two bytes of `s` are
146+ /// assumed to be the two digits of the year.
147+ fn get_year ( s : & str ) -> u8 {
148+ let bytes = s. as_bytes ( ) ;
149+ let n = bytes. len ( ) ;
150+ let y1 = bytes[ n - 2 ] - b'0' ;
151+ let y2 = bytes[ n - 1 ] - b'0' ;
152+ 10 * y1 + y2
153+ }
154+
155+ /// Whether the first filename should be interpreted as a timestamp.
156+ fn is_first_filename_timestamp (
157+ reference : Option < & OsString > ,
158+ date : Option < & str > ,
159+ timestamp : & Option < String > ,
160+ files : & [ & String ] ,
161+ ) -> bool {
162+ match std:: env:: var ( "_POSIX2_VERSION" ) {
163+ Ok ( s) if s == "199209" => {
164+ if timestamp. is_none ( ) && reference. is_none ( ) && date. is_none ( ) && files. len ( ) >= 2 {
165+ let s = files[ 0 ] ;
166+ all_digits ( s)
167+ && ( s. len ( ) == 8 || ( s. len ( ) == 10 && ( 69 ..=99 ) . contains ( & get_year ( s) ) ) )
168+ } else {
169+ false
170+ }
171+ }
172+ _ => false ,
173+ }
174+ }
175+
176+ /// Cycle the last two characters to the beginning of the string.
177+ ///
178+ /// `s` must have length at least two.
179+ fn shr2 ( s : & str ) -> String {
180+ let n = s. len ( ) ;
181+ let ( a, b) = s. split_at ( n - 2 ) ;
182+ let mut result = String :: with_capacity ( n) ;
183+ result. push_str ( b) ;
184+ result. push_str ( a) ;
185+ result
186+ }
187+
138188#[ uucore:: main]
139189pub fn uumain ( args : impl uucore:: Args ) -> UResult < ( ) > {
140190 let matches = uu_app ( ) . try_get_matches_from ( args) ?;
141191
142- let files : Vec < InputFile > = matches
143- . get_many :: < OsString > ( ARG_FILES )
192+ let mut filenames : Vec < & String > = matches
193+ . get_many :: < String > ( ARG_FILES )
144194 . ok_or_else ( || {
145195 USimpleError :: new (
146196 1 ,
@@ -150,31 +200,46 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
150200 ) ,
151201 )
152202 } ) ?
153- . map ( |filename| {
154- if filename == "-" {
155- InputFile :: Stdout
156- } else {
157- InputFile :: Path ( PathBuf :: from ( filename) )
158- }
159- } )
160203 . collect ( ) ;
161204
162205 let no_deref = matches. get_flag ( options:: NO_DEREF ) ;
163206
164207 let reference = matches. get_one :: < OsString > ( options:: sources:: REFERENCE ) ;
165- let timestamp = matches. get_one :: < String > ( options:: sources:: TIMESTAMP ) ;
208+ let date = matches
209+ . get_one :: < String > ( options:: sources:: DATE )
210+ . map ( |date| date. to_owned ( ) ) ;
211+
212+ let mut timestamp = matches
213+ . get_one :: < String > ( options:: sources:: TIMESTAMP )
214+ . map ( |t| t. to_owned ( ) ) ;
215+
216+ if is_first_filename_timestamp ( reference, date. as_deref ( ) , & timestamp, & filenames) {
217+ timestamp = if filenames[ 0 ] . len ( ) == 10 {
218+ Some ( shr2 ( filenames[ 0 ] ) )
219+ } else {
220+ Some ( filenames[ 0 ] . to_string ( ) )
221+ } ;
222+ filenames = filenames[ 1 ..] . to_vec ( ) ;
223+ }
166224
167225 let source = if let Some ( reference) = reference {
168226 Source :: Reference ( PathBuf :: from ( reference) )
169227 } else if let Some ( ts) = timestamp {
170- Source :: Timestamp ( parse_timestamp ( ts) ?)
228+ Source :: Timestamp ( parse_timestamp ( & ts) ?)
171229 } else {
172230 Source :: Now
173231 } ;
174232
175- let date = matches
176- . get_one :: < String > ( options:: sources:: DATE )
177- . map ( |date| date. to_owned ( ) ) ;
233+ let files: Vec < InputFile > = filenames
234+ . into_iter ( )
235+ . map ( |filename| {
236+ if filename == "-" {
237+ InputFile :: Stdout
238+ } else {
239+ InputFile :: Path ( PathBuf :: from ( filename) )
240+ }
241+ } )
242+ . collect ( ) ;
178243
179244 let opts = Options {
180245 no_create : matches. get_flag ( options:: NO_CREATE ) ,
@@ -275,7 +340,6 @@ pub fn uu_app() -> Command {
275340 Arg :: new ( ARG_FILES )
276341 . action ( ArgAction :: Append )
277342 . num_args ( 1 ..)
278- . value_parser ( ValueParser :: os_string ( ) )
279343 . value_hint ( clap:: ValueHint :: AnyPath ) ,
280344 )
281345 . group (
0 commit comments